agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v2] WIP: Evaluate arguments of correlated SubPlans in the referencing ExprState
383+ messages / 5 participants
[nested] [flat]

* [PATCH v1] WIP: Evaluate arguments of correlated SubPlans in the referencing ExprState
@ 2023-02-25 21:39 Andres Freund <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Andres Freund @ 2023-02-25 21:39 UTC (permalink / raw)

---
 src/include/nodes/execnodes.h       |  1 -
 src/backend/executor/execExpr.c     | 81 +++++++++++++++++------------
 src/backend/executor/execProcnode.c |  5 ++
 src/backend/executor/nodeSubplan.c  | 30 +++++------
 4 files changed, 66 insertions(+), 51 deletions(-)

diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 20f4c8b35f3..437cf8b5a02 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -947,7 +947,6 @@ typedef struct SubPlanState
 	struct PlanState *planstate;	/* subselect plan's state tree */
 	struct PlanState *parent;	/* parent plan node's state tree */
 	ExprState  *testexpr;		/* state of combining expression */
-	List	   *args;			/* states of argument expression(s) */
 	HeapTuple	curTuple;		/* copy of most recent tuple from subplan */
 	Datum		curArray;		/* most recent array from ARRAY() subplan */
 	/* these are used when hashing the subselect's output: */
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index c61f23c6c18..7a9d5729b4b 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -87,6 +87,9 @@ static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
 								  FunctionCallInfo fcinfo, AggStatePerTrans pertrans,
 								  int transno, int setno, int setoff, bool ishash,
 								  bool nullcheck);
+static void ExecInitSubPlanExpr(SubPlan *subplan,
+								ExprState *state,
+								Datum *resv, bool *resnull);
 
 
 /*
@@ -1388,7 +1391,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
 		case T_SubPlan:
 			{
 				SubPlan    *subplan = (SubPlan *) node;
-				SubPlanState *sstate;
 
 				/*
 				 * Real execution of a MULTIEXPR SubPlan has already been
@@ -1405,19 +1407,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 					break;
 				}
 
-				if (!state->parent)
-					elog(ERROR, "SubPlan found with no parent plan");
-
-				sstate = ExecInitSubPlan(subplan, state->parent);
-
-				/* add SubPlanState nodes to state->parent->subPlan */
-				state->parent->subPlan = lappend(state->parent->subPlan,
-												 sstate);
-
-				scratch.opcode = EEOP_SUBPLAN;
-				scratch.d.subplan.sstate = sstate;
-
-				ExprEvalPushStep(state, &scratch);
+				ExecInitSubPlanExpr(subplan, state, resv, resnull);
 				break;
 			}
 
@@ -2618,29 +2608,12 @@ ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
 	foreach(lc, info->multiexpr_subplans)
 	{
 		SubPlan    *subplan = (SubPlan *) lfirst(lc);
-		SubPlanState *sstate;
 
 		Assert(subplan->subLinkType == MULTIEXPR_SUBLINK);
 
-		/* This should match what ExecInitExprRec does for other SubPlans: */
-
-		if (!state->parent)
-			elog(ERROR, "SubPlan found with no parent plan");
-
-		sstate = ExecInitSubPlan(subplan, state->parent);
-
-		/* add SubPlanState nodes to state->parent->subPlan */
-		state->parent->subPlan = lappend(state->parent->subPlan,
-										 sstate);
-
-		scratch.opcode = EEOP_SUBPLAN;
-		scratch.d.subplan.sstate = sstate;
-
 		/* The result can be ignored, but we better put it somewhere */
-		scratch.resvalue = &state->resvalue;
-		scratch.resnull = &state->resnull;
-
-		ExprEvalPushStep(state, &scratch);
+		ExecInitSubPlanExpr(subplan, state,
+							&state->resvalue, &state->resnull);
 	}
 }
 
@@ -4040,3 +4013,45 @@ ExecBuildParamSetEqual(TupleDesc desc,
 
 	return state;
 }
+
+static void
+ExecInitSubPlanExpr(SubPlan *subplan,
+					ExprState *state,
+					Datum *resv, bool *resnull)
+{
+	ExprEvalStep scratch = {0};
+	SubPlanState *sstate;
+	ListCell   *pvar;
+	ListCell   *l;
+	EState	   *estate = state->parent->state;
+
+	if (!state->parent)
+		elog(ERROR, "SubPlan found with no parent plan");
+
+	/*
+	 * Generate steps to evaluate input arguments for the subplan.
+	 *
+	 * Any calculation we have to do can be done in the parent econtext, since
+	 * the Param values don't need to have per-query lifetime.
+	 */
+	forboth(l, subplan->parParam, pvar, subplan->args)
+	{
+		int			paramid = lfirst_int(l);
+		ParamExecData *prm = &estate->es_param_exec_vals[paramid];
+
+		ExecInitExprRec(lfirst(pvar), state, &prm->value, &prm->isnull);
+	}
+
+	sstate = ExecInitSubPlan(subplan, state->parent);
+
+	/* add SubPlanState nodes to state->parent->subPlan */
+	state->parent->subPlan = lappend(state->parent->subPlan,
+									 sstate);
+
+	scratch.opcode = EEOP_SUBPLAN;
+	scratch.resvalue = resv;
+	scratch.resnull = resnull;
+	scratch.d.subplan.sstate = sstate;
+
+	ExprEvalPushStep(state, &scratch);
+}
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 4d288bc8d41..f62bb28140f 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -393,6 +393,10 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
 	/*
 	 * Initialize any initPlans present in this node.  The planner put them in
 	 * a separate list for us.
+	 *
+	 * The defining characteristic of initplans is that they don't have
+	 * arguments, so we don't need to evaluate them (in contrast to
+	 * ExecInitSubPlanExpr()).
 	 */
 	subps = NIL;
 	foreach(l, node->initPlan)
@@ -401,6 +405,7 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
 		SubPlanState *sstate;
 
 		Assert(IsA(subplan, SubPlan));
+		Assert(subplan->args == NIL);
 		sstate = ExecInitSubPlan(subplan, result);
 		subps = lappend(subps, sstate);
 	}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index c136f75ac24..3458ac007cd 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -107,7 +107,7 @@ ExecHashSubPlan(SubPlanState *node,
 	TupleTableSlot *slot;
 
 	/* Shouldn't have any direct correlation Vars */
-	if (subplan->parParam != NIL || node->args != NIL)
+	if (subplan->parParam != NIL || subplan->args != NIL)
 		elog(ERROR, "hashed subplan with direct correlation not supported");
 
 	/*
@@ -231,7 +231,6 @@ ExecScanSubPlan(SubPlanState *node,
 	TupleTableSlot *slot;
 	Datum		result;
 	bool		found = false;	/* true if got at least one subplan tuple */
-	ListCell   *pvar;
 	ListCell   *l;
 	ArrayBuildStateAny *astate = NULL;
 
@@ -248,26 +247,20 @@ ExecScanSubPlan(SubPlanState *node,
 	oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
 
 	/*
-	 * Set Params of this plan from parent plan correlation values. (Any
-	 * calculation we have to do is done in the parent econtext, since the
-	 * Param values don't need to have per-query lifetime.)
+	 * We rely on the caller to evaluate plan correlation values, if
+	 * necessary. However we still need to record the fact that the values
+	 * (might have) changed, otherwise the ExecReScan() below won't know that
+	 * nodes need to be rescanned.
 	 */
-	Assert(list_length(subplan->parParam) == list_length(node->args));
-
-	forboth(l, subplan->parParam, pvar, node->args)
+	Assert(list_length(subplan->parParam) == list_length(subplan->args));
+	foreach(l, subplan->parParam)
 	{
 		int			paramid = lfirst_int(l);
-		ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
 
-		prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
-											   econtext,
-											   &(prm->isnull));
 		planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
 	}
 
-	/*
-	 * Now that we've set up its parameters, we can reset the subplan.
-	 */
+	/* with that done, we can reset the subplan */
 	ExecReScan(planstate);
 
 	/*
@@ -817,6 +810,10 @@ slotNoNulls(TupleTableSlot *slot)
  * as well as regular SubPlans.  Note that we don't link the SubPlan into
  * the parent's subPlan list, because that shouldn't happen for InitPlans.
  * Instead, ExecInitExpr() does that one part.
+ *
+ * We also rely on ExecInitExpr(), more precisely ExecInitSubPlanExpr(), to
+ * evaluate input parameters, as that allows them to be evaluated as part of
+ * the expression referencing the SubPlan.
  * ----------------------------------------------------------------
  */
 SubPlanState *
@@ -844,7 +841,6 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
 
 	/* Initialize subexpressions */
 	sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
-	sstate->args = ExecInitExprList(subplan->args, parent);
 
 	/*
 	 * initialize my state
@@ -1107,7 +1103,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 		elog(ERROR, "ANY/ALL subselect unsupported as initplan");
 	if (subLinkType == CTE_SUBLINK)
 		elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
-	if (subplan->parParam || node->args)
+	if (subplan->parParam || subplan->args)
 		elog(ERROR, "correlated subplans should not be executed via ExecSetParamPlan");
 
 	/*
-- 
2.38.0


--6ir4gcdcv6d4j3qy--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2] WIP: Evaluate arguments of correlated SubPlans in the referencing ExprState
@ 2023-02-25 21:39 Andres Freund <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Andres Freund @ 2023-02-25 21:39 UTC (permalink / raw)

---
 src/include/executor/execExpr.h       |  6 +-
 src/include/nodes/execnodes.h         |  1 -
 src/backend/executor/execExpr.c       | 93 +++++++++++++++++----------
 src/backend/executor/execExprInterp.c | 22 +++++++
 src/backend/executor/execProcnode.c   |  5 ++
 src/backend/executor/nodeSubplan.c    | 30 ++++-----
 src/backend/jit/llvm/llvmjit_expr.c   |  6 ++
 src/backend/jit/llvm/llvmjit_types.c  |  1 +
 8 files changed, 112 insertions(+), 52 deletions(-)

diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index 06c3adc0a19..ca2b7306cd0 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -158,6 +158,8 @@ typedef enum ExprEvalOp
 	EEOP_PARAM_EXEC,
 	EEOP_PARAM_EXTERN,
 	EEOP_PARAM_CALLBACK,
+	/* set PARAM_EXEC value */
+	EEOP_PARAM_SET,
 
 	/* return CaseTestExpr value */
 	EEOP_CASE_TESTVAL,
@@ -374,7 +376,7 @@ typedef struct ExprEvalStep
 			ExprEvalRowtypeCache rowcache;
 		}			nulltest_row;
 
-		/* for EEOP_PARAM_EXEC/EXTERN */
+		/* for EEOP_PARAM_EXEC/EXTERN and EEOP_PARAM_SET */
 		struct
 		{
 			int			paramid;	/* numeric ID for parameter */
@@ -738,6 +740,8 @@ extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
 							  ExprContext *econtext);
 extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
 								ExprContext *econtext);
+extern void ExecEvalParamSet(ExprState *state, ExprEvalStep *op,
+							 ExprContext *econtext);
 extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
 extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
 extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index e7eb1e666ff..16e95e4cb48 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -947,7 +947,6 @@ typedef struct SubPlanState
 	struct PlanState *planstate;	/* subselect plan's state tree */
 	struct PlanState *parent;	/* parent plan node's state tree */
 	ExprState  *testexpr;		/* state of combining expression */
-	List	   *args;			/* states of argument expression(s) */
 	HeapTuple	curTuple;		/* copy of most recent tuple from subplan */
 	Datum		curArray;		/* most recent array from ARRAY() subplan */
 	/* these are used when hashing the subselect's output: */
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index c61f23c6c18..002f2a0091f 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -87,6 +87,9 @@ static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
 								  FunctionCallInfo fcinfo, AggStatePerTrans pertrans,
 								  int transno, int setno, int setoff, bool ishash,
 								  bool nullcheck);
+static void ExecInitSubPlanExpr(SubPlan *subplan,
+								ExprState *state,
+								Datum *resv, bool *resnull);
 
 
 /*
@@ -1388,7 +1391,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
 		case T_SubPlan:
 			{
 				SubPlan    *subplan = (SubPlan *) node;
-				SubPlanState *sstate;
 
 				/*
 				 * Real execution of a MULTIEXPR SubPlan has already been
@@ -1405,19 +1407,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 					break;
 				}
 
-				if (!state->parent)
-					elog(ERROR, "SubPlan found with no parent plan");
-
-				sstate = ExecInitSubPlan(subplan, state->parent);
-
-				/* add SubPlanState nodes to state->parent->subPlan */
-				state->parent->subPlan = lappend(state->parent->subPlan,
-												 sstate);
-
-				scratch.opcode = EEOP_SUBPLAN;
-				scratch.d.subplan.sstate = sstate;
-
-				ExprEvalPushStep(state, &scratch);
+				ExecInitSubPlanExpr(subplan, state, resv, resnull);
 				break;
 			}
 
@@ -2618,29 +2608,12 @@ ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
 	foreach(lc, info->multiexpr_subplans)
 	{
 		SubPlan    *subplan = (SubPlan *) lfirst(lc);
-		SubPlanState *sstate;
 
 		Assert(subplan->subLinkType == MULTIEXPR_SUBLINK);
 
-		/* This should match what ExecInitExprRec does for other SubPlans: */
-
-		if (!state->parent)
-			elog(ERROR, "SubPlan found with no parent plan");
-
-		sstate = ExecInitSubPlan(subplan, state->parent);
-
-		/* add SubPlanState nodes to state->parent->subPlan */
-		state->parent->subPlan = lappend(state->parent->subPlan,
-										 sstate);
-
-		scratch.opcode = EEOP_SUBPLAN;
-		scratch.d.subplan.sstate = sstate;
-
 		/* The result can be ignored, but we better put it somewhere */
-		scratch.resvalue = &state->resvalue;
-		scratch.resnull = &state->resnull;
-
-		ExprEvalPushStep(state, &scratch);
+		ExecInitSubPlanExpr(subplan, state,
+							&state->resvalue, &state->resnull);
 	}
 }
 
@@ -4040,3 +4013,57 @@ ExecBuildParamSetEqual(TupleDesc desc,
 
 	return state;
 }
+
+static void
+ExecInitSubPlanExpr(SubPlan *subplan,
+					ExprState *state,
+					Datum *resv, bool *resnull)
+{
+	ExprEvalStep scratch = {0};
+	SubPlanState *sstate;
+	ListCell   *pvar;
+	ListCell   *l;
+
+	if (!state->parent)
+		elog(ERROR, "SubPlan found with no parent plan");
+
+	/*
+	 * Generate steps to evaluate input arguments for the subplan.
+	 *
+	 * We evaluate the argument expressions into ExprState's resvalue/resnull,
+	 * and then use PARAM_SET to update the parameter. We do that, instead of
+	 * evaluating directly into the param, to avoid depending on the pointer
+	 * value remaining stable / being included in the generated expression. No
+	 * danger of conflicts with other uses of resvalue/resnull as storing and
+	 * using the value always is in subsequent steps.
+	 *
+	 * Any calculation we have to do can be done in the parent econtext, since
+	 * the Param values don't need to have per-query lifetime.
+	 */
+	forboth(l, subplan->parParam, pvar, subplan->args)
+	{
+		int			paramid = lfirst_int(l);
+
+		ExecInitExprRec(lfirst(pvar), state,
+						&state->resvalue, &state->resnull);
+
+		scratch.opcode = EEOP_PARAM_SET;
+		scratch.d.param.paramid = paramid;
+		/* type isn't needed, but an old value could be confusing */
+		scratch.d.param.paramtype = InvalidOid;
+		ExprEvalPushStep(state, &scratch);
+	}
+
+	sstate = ExecInitSubPlan(subplan, state->parent);
+
+	/* add SubPlanState nodes to state->parent->subPlan */
+	state->parent->subPlan = lappend(state->parent->subPlan,
+									 sstate);
+
+	scratch.opcode = EEOP_SUBPLAN;
+	scratch.resvalue = resv;
+	scratch.resnull = resnull;
+	scratch.d.subplan.sstate = sstate;
+
+	ExprEvalPushStep(state, &scratch);
+}
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 19351fe34bf..3cab8a5cdae 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -446,6 +446,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 		&&CASE_EEOP_PARAM_EXEC,
 		&&CASE_EEOP_PARAM_EXTERN,
 		&&CASE_EEOP_PARAM_CALLBACK,
+		&&CASE_EEOP_PARAM_SET,
 		&&CASE_EEOP_CASE_TESTVAL,
 		&&CASE_EEOP_MAKE_READONLY,
 		&&CASE_EEOP_IOCOERCE,
@@ -1081,6 +1082,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 			EEO_NEXT();
 		}
 
+		EEO_CASE(EEOP_PARAM_SET)
+		{
+			/* out of line, unlikely to matter performancewise */
+			ExecEvalParamSet(state, op, econtext);
+			EEO_NEXT();
+		}
+
 		EEO_CASE(EEOP_CASE_TESTVAL)
 		{
 			/*
@@ -2477,6 +2485,20 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 			 errmsg("no value found for parameter %d", paramId)));
 }
 
+/*
+ * Set value of a param (currently always PARAM_EXEC) from
+ * state->res{value,null}.
+ */
+void
+ExecEvalParamSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
+{
+	ParamExecData *prm;
+
+	prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
+	prm->value = state->resvalue;
+	prm->isnull = state->resnull;
+}
+
 /*
  * Raise error if a CURRENT OF expression is evaluated.
  *
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 4d288bc8d41..f62bb28140f 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -393,6 +393,10 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
 	/*
 	 * Initialize any initPlans present in this node.  The planner put them in
 	 * a separate list for us.
+	 *
+	 * The defining characteristic of initplans is that they don't have
+	 * arguments, so we don't need to evaluate them (in contrast to
+	 * ExecInitSubPlanExpr()).
 	 */
 	subps = NIL;
 	foreach(l, node->initPlan)
@@ -401,6 +405,7 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
 		SubPlanState *sstate;
 
 		Assert(IsA(subplan, SubPlan));
+		Assert(subplan->args == NIL);
 		sstate = ExecInitSubPlan(subplan, result);
 		subps = lappend(subps, sstate);
 	}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index c136f75ac24..3458ac007cd 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -107,7 +107,7 @@ ExecHashSubPlan(SubPlanState *node,
 	TupleTableSlot *slot;
 
 	/* Shouldn't have any direct correlation Vars */
-	if (subplan->parParam != NIL || node->args != NIL)
+	if (subplan->parParam != NIL || subplan->args != NIL)
 		elog(ERROR, "hashed subplan with direct correlation not supported");
 
 	/*
@@ -231,7 +231,6 @@ ExecScanSubPlan(SubPlanState *node,
 	TupleTableSlot *slot;
 	Datum		result;
 	bool		found = false;	/* true if got at least one subplan tuple */
-	ListCell   *pvar;
 	ListCell   *l;
 	ArrayBuildStateAny *astate = NULL;
 
@@ -248,26 +247,20 @@ ExecScanSubPlan(SubPlanState *node,
 	oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
 
 	/*
-	 * Set Params of this plan from parent plan correlation values. (Any
-	 * calculation we have to do is done in the parent econtext, since the
-	 * Param values don't need to have per-query lifetime.)
+	 * We rely on the caller to evaluate plan correlation values, if
+	 * necessary. However we still need to record the fact that the values
+	 * (might have) changed, otherwise the ExecReScan() below won't know that
+	 * nodes need to be rescanned.
 	 */
-	Assert(list_length(subplan->parParam) == list_length(node->args));
-
-	forboth(l, subplan->parParam, pvar, node->args)
+	Assert(list_length(subplan->parParam) == list_length(subplan->args));
+	foreach(l, subplan->parParam)
 	{
 		int			paramid = lfirst_int(l);
-		ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
 
-		prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
-											   econtext,
-											   &(prm->isnull));
 		planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
 	}
 
-	/*
-	 * Now that we've set up its parameters, we can reset the subplan.
-	 */
+	/* with that done, we can reset the subplan */
 	ExecReScan(planstate);
 
 	/*
@@ -817,6 +810,10 @@ slotNoNulls(TupleTableSlot *slot)
  * as well as regular SubPlans.  Note that we don't link the SubPlan into
  * the parent's subPlan list, because that shouldn't happen for InitPlans.
  * Instead, ExecInitExpr() does that one part.
+ *
+ * We also rely on ExecInitExpr(), more precisely ExecInitSubPlanExpr(), to
+ * evaluate input parameters, as that allows them to be evaluated as part of
+ * the expression referencing the SubPlan.
  * ----------------------------------------------------------------
  */
 SubPlanState *
@@ -844,7 +841,6 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
 
 	/* Initialize subexpressions */
 	sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
-	sstate->args = ExecInitExprList(subplan->args, parent);
 
 	/*
 	 * initialize my state
@@ -1107,7 +1103,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 		elog(ERROR, "ANY/ALL subselect unsupported as initplan");
 	if (subLinkType == CTE_SUBLINK)
 		elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
-	if (subplan->parParam || node->args)
+	if (subplan->parParam || subplan->args)
 		elog(ERROR, "correlated subplans should not be executed via ExecSetParamPlan");
 
 	/*
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 1c722c79552..812f8758743 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -1094,6 +1094,12 @@ llvm_compile_expr(ExprState *state)
 					break;
 				}
 
+			case EEOP_PARAM_SET:
+				build_EvalXFunc(b, mod, "ExecEvalParamSet",
+								v_state, op, v_econtext);
+				LLVMBuildBr(b, opblocks[opno + 1]);
+				break;
+
 			case EEOP_SBSREF_SUBSCRIPTS:
 				{
 					int			jumpdone = op->d.sbsref_subscript.jumpdone;
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 876fb640294..0b1df3afe00 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -123,6 +123,7 @@ void	   *referenced_functions[] =
 	ExecEvalNextValueExpr,
 	ExecEvalParamExec,
 	ExecEvalParamExtern,
+	ExecEvalParamSet,
 	ExecEvalRow,
 	ExecEvalRowNotNull,
 	ExecEvalRowNull,
-- 
2.37.1.188.g71a8fab31b


--2fo66m5ddj2bowyf--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v29 08/11] Add aggregates support in IVM
@ 2023-05-31 11:46 Yugo Nagata <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Yugo Nagata @ 2023-05-31 11:46 UTC (permalink / raw)

count, sum, adn avg are supported.

As a restriction, expressions specified in GROUP BY must appear in
the target list because tuples to be updated in IMMV are identified
by using this group key. However, in the case of aggregates without
GROUP BY, there is only one tuple in the view, so keys are not uses
to identify tuples.

When creating a IMMV, in addition to __ivm_count column, some hidden
columns for each aggregate are added to the target list. For example,
names of these hidden columns are ivm_count_avg and ivm_sum_avg for
the average function, and so on.

When a base table is modified, the aggregated values and related
hidden columns are also updated as well as __ivm_count__. The
way of update depends the kind of aggregate function.=E3=80=80Specifically,
sum and count are updated by simply adding or subtracting delta value
calculated from delta tables. avg is updated by using values of sum
and count stored in views as hidden columns and deltas calculated
from delta tables.

About aggregate functions except "count()" (sum and avg), NULLs in input
values are ignored, and the result of aggegate should be NULL when no
rows are selected.  To support this specification, the numbers of non-NULL
input values are counted and stored in hidden columns. In the case of
count(), count(x) returns zero when no rows are selected, but count(*)
doesn't ignore NULL input.
---
 src/backend/commands/createas.c | 264 +++++++++++++++++--
 src/backend/commands/matview.c  | 433 ++++++++++++++++++++++++++++++--
 src/include/commands/createas.h |   1 +
 3 files changed, 661 insertions(+), 37 deletions(-)

diff --git a/src/backend/commands/createas.c b/src/backend/commands/createa=
s.c
index 076f35ee6b..c8aa558f2e 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -54,14 +54,19 @@
 #include "parser/parsetree.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_func.h"
+#include "parser/parse_type.h"
 #include "rewrite/rewriteHandler.h"
+#include "rewrite/rewriteManip.h"
 #include "storage/smgr.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
+#include "utils/regproc.h"
+#include "utils/fmgroids.h"
 #include "utils/rel.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
+#include "utils/syscache.h"
=20
 typedef struct
 {
@@ -75,6 +80,11 @@ typedef struct
 	BulkInsertState bistate;	/* bulk insert state */
 } DR_intorel;
=20
+typedef struct
+{
+	bool	has_agg;
+} check_ivm_restriction_context;
+
 /* utility functions for CTAS definition creation */
 static ObjectAddress create_ctas_internal(List *attrList, IntoClause *into=
);
 static ObjectAddress create_ctas_nodata(List *tlist, IntoClause *into);
@@ -89,8 +99,9 @@ static void CreateIvmTriggersOnBaseTablesRecurse(Query *q=
ry, Node *node, Oid mat
 									 Relids *relids, bool ex_lock);
 static void CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 ti=
ming, bool ex_lock);
 static void check_ivm_restriction(Node *node);
-static bool check_ivm_restriction_walker(Node *node, void *context);
+static bool check_ivm_restriction_walker(Node *node, check_ivm_restriction=
_context *context);
 static Bitmapset *get_primary_key_attnos_from_query(Query *query, List **c=
onstraintList);
+static bool check_aggregate_supports_ivm(Oid aggfnoid);
=20
 /*
  * create_ctas_internal
@@ -421,6 +432,7 @@ ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt=
 *stmt,
  * rewriteQueryForIMMV -- rewrite view definition query for IMMV
  *
  * count(*) is added for counting distinct tuples in views.
+ * Also, additional hidden columns are added for aggregate values.
  */
 Query *
 rewriteQueryForIMMV(Query *query, List *colNames)
@@ -434,16 +446,49 @@ rewriteQueryForIMMV(Query *query, List *colNames)
 	rewritten =3D copyObject(query);
 	pstate->p_expr_kind =3D EXPR_KIND_SELECT_TARGET;
=20
-	/*
-	 * Convert DISTINCT to GROUP BY and add count(*) for counting distinct
-	 * tuples in views.
-	 */
-	if (rewritten->distinctClause)
+	/* group keys must be in targetlist */
+	if (rewritten->groupClause)
 	{
-		TargetEntry *tle;
+		ListCell *lc;
+		foreach(lc, rewritten->groupClause)
+		{
+			SortGroupClause *scl =3D (SortGroupClause *) lfirst(lc);
+			TargetEntry *tle =3D get_sortgroupclause_tle(scl, rewritten->targetList=
);
=20
+			if (tle->resjunk)
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("GROUP BY expression not appearing in select list is not sup=
ported on incrementally maintainable materialized view")));
+		}
+	}
+	/* Convert DISTINCT to GROUP BY.  count(*) will be added afterward. */
+	else if (!rewritten->hasAggs && rewritten->distinctClause)
 		rewritten->groupClause =3D transformDistinctClause(NULL, &rewritten->tar=
getList, rewritten->sortClause, false);
=20
+	/* Add additional columns for aggregate values */
+	if (rewritten->hasAggs)
+	{
+		ListCell *lc;
+		List *aggs =3D NIL;
+		AttrNumber next_resno =3D list_length(rewritten->targetList) + 1;
+
+		foreach(lc, rewritten->targetList)
+		{
+			TargetEntry *tle =3D (TargetEntry *) lfirst(lc);
+			char *resname =3D (colNames =3D=3D NIL || foreach_current_index(lc) >=
=3D list_length(colNames) ?
+								tle->resname : strVal(list_nth(colNames, tle->resno - 1)));
+
+			if (IsA(tle->expr, Aggref))
+				makeIvmAggColumn(pstate, (Aggref *) tle->expr, resname, &next_resno, &=
aggs);
+		}
+		rewritten->targetList =3D list_concat(rewritten->targetList, aggs);
+	}
+
+	/* Add count(*) for counting distinct tuples in views */
+	if (rewritten->distinctClause || rewritten->hasAggs)
+	{
+		TargetEntry *tle;
+
 		fn =3D makeFuncCall(SystemFuncName("count"), NIL, COERCE_EXPLICIT_CALL, =
-1);
 		fn->agg_star =3D true;
=20
@@ -460,6 +505,91 @@ rewriteQueryForIMMV(Query *query, List *colNames)
 	return rewritten;
 }
=20
+/*
+ * makeIvmAggColumn -- make additional aggregate columns for IVM
+ *
+ * For an aggregate column specified by aggref, additional aggregate colum=
ns
+ * are added, which are used to calculate the new aggregate value in IMMV.
+ * An additional aggregate columns has a name based on resname
+ * (ex. ivm_count_resname), and resno specified by next_resno. The created
+ * columns are returned to aggs, and the resno for the next column is also
+ * returned to next_resno.
+ *
+ * Currently, an additional count() is created for aggref other than count.
+ * In addition, sum() is created for avg aggregate column.
+ */
+void
+makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname, AttrNu=
mber *next_resno, List **aggs)
+{
+	TargetEntry *tle_count;
+	Node *node;
+	FuncCall *fn;
+	Const	*dmy_arg =3D makeConst(INT4OID,
+								 -1,
+								 InvalidOid,
+								 sizeof(int32),
+								 Int32GetDatum(1),
+								 false,
+								 true); /* pass by value */
+	const char *aggname =3D get_func_name(aggref->aggfnoid);
+
+	/*
+	 * For aggregate functions except count, add count() func with the same a=
rg parameters.
+	 * This count result is used for determining if the aggregate value shoul=
d be NULL or not.
+	 * Also, add sum() func for avg because we need to calculate an average v=
alue as sum/count.
+	 *
+	 * XXX: If there are same expressions explicitly in the target list, we c=
an use this instead
+	 * of adding new duplicated one.
+	 */
+	if (strcmp(aggname, "count") !=3D 0)
+	{
+		fn =3D makeFuncCall(SystemFuncName("count"), NIL, COERCE_EXPLICIT_CALL, =
-1);
+
+		/* Make a Func with a dummy arg, and then override this by the original =
agg's args. */
+		node =3D ParseFuncOrColumn(pstate, fn->funcname, list_make1(dmy_arg), NU=
LL, fn, false, -1);
+		((Aggref *)node)->args =3D aggref->args;
+
+		tle_count =3D makeTargetEntry((Expr *) node,
+									*next_resno,
+									pstrdup(makeObjectName("__ivm_count",resname, "_")),
+									false);
+		*aggs =3D lappend(*aggs, tle_count);
+		(*next_resno)++;
+	}
+	if (strcmp(aggname, "avg") =3D=3D 0)
+	{
+		List *dmy_args =3D NIL;
+		ListCell *lc;
+		foreach(lc, aggref->aggargtypes)
+		{
+			Oid		typeid =3D lfirst_oid(lc);
+			Type	type =3D typeidType(typeid);
+
+			Const *con =3D makeConst(typeid,
+								   -1,
+								   typeTypeCollation(type),
+								   typeLen(type),
+								   (Datum) 0,
+								   true,
+								   typeByVal(type));
+			dmy_args =3D lappend(dmy_args, con);
+			ReleaseSysCache(type);
+		}
+		fn =3D makeFuncCall(SystemFuncName("sum"), NIL, COERCE_EXPLICIT_CALL, -1=
);
+
+		/* Make a Func with dummy args, and then override this by the original a=
gg's args. */
+		node =3D ParseFuncOrColumn(pstate, fn->funcname, dmy_args, NULL, fn, fal=
se, -1);
+		((Aggref *)node)->args =3D aggref->args;
+
+		tle_count =3D makeTargetEntry((Expr *) node,
+									*next_resno,
+									pstrdup(makeObjectName("__ivm_sum",resname, "_")),
+									false);
+		*aggs =3D lappend(*aggs, tle_count);
+		(*next_resno)++;
+	}
+}
+
 /*
  * GetIntoRelEFlags --- compute executor flags needed for CREATE TABLE AS
  *
@@ -943,11 +1073,13 @@ CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type=
, int16 timing, bool ex_lock
 static void
 check_ivm_restriction(Node *node)
 {
-	check_ivm_restriction_walker(node, NULL);
+	check_ivm_restriction_context context =3D {false};
+
+	check_ivm_restriction_walker(node, &context);
 }
=20
 static bool
-check_ivm_restriction_walker(Node *node, void *context)
+check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *co=
ntext)
 {
 	if (node =3D=3D NULL)
 		return false;
@@ -976,6 +1108,10 @@ check_ivm_restriction_walker(Node *node, void *contex=
t)
 					ereport(ERROR,
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 							 errmsg("CTE is not supported on incrementally maintainable materia=
lized view")));
+				if (qry->groupClause !=3D NIL && !qry->hasAggs)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("GROUP BY clause without aggregate is not supported on incr=
ementally maintainable materialized view")));
 				if (qry->havingQual !=3D NULL)
 					ereport(ERROR,
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1028,6 +1164,8 @@ check_ivm_restriction_walker(Node *node, void *contex=
t)
 					}
 				}
=20
+				context->has_agg |=3D qry->hasAggs;
+
 				/* restrictions for rtable */
 				foreach(lc, qry->rtable)
 				{
@@ -1076,7 +1214,7 @@ check_ivm_restriction_walker(Node *node, void *contex=
t)
=20
 				}
=20
-				query_tree_walker(qry, check_ivm_restriction_walker, NULL, QTW_IGNORE_=
RANGE_TABLE);
+				query_tree_walker(qry, check_ivm_restriction_walker, (void *) context,=
 QTW_IGNORE_RANGE_TABLE);
=20
 				break;
 			}
@@ -1087,8 +1225,12 @@ check_ivm_restriction_walker(Node *node, void *conte=
xt)
 						ereport(ERROR,
 								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 								 errmsg("column name %s is not supported on incrementally maintain=
able materialized view", tle->resname)));
+				if (context->has_agg && !IsA(tle->expr, Aggref) && contain_aggs_of_lev=
el((Node *) tle->expr, 0))
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("expression containing an aggregate in it is not supported =
on incrementally maintainable materialized view")));
=20
-				expression_tree_walker(node, check_ivm_restriction_walker, NULL);
+				expression_tree_walker(node, check_ivm_restriction_walker, (void *) co=
ntext);
 				break;
 			}
 		case T_JoinExpr:
@@ -1100,14 +1242,36 @@ check_ivm_restriction_walker(Node *node, void *cont=
ext)
 								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 								 errmsg("OUTER JOIN is not supported on incrementally maintainable=
 materialized view")));
=20
-				expression_tree_walker(node, check_ivm_restriction_walker, NULL);
+				expression_tree_walker(node, check_ivm_restriction_walker, (void *) co=
ntext);
+				break;
 			}
-			break;
 		case T_Aggref:
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("aggregate function is not supported on incrementally maintai=
nable materialized view")));
-			break;
+			{
+				/* Check if this supports IVM */
+				Aggref *aggref =3D (Aggref *) node;
+				const char *aggname =3D format_procedure(aggref->aggfnoid);
+
+				if (aggref->aggfilter !=3D NULL)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("aggregate function with FILTER clause is not supported on =
incrementally maintainable materialized view")));
+
+				if (aggref->aggdistinct !=3D NULL)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("aggregate function with DISTINCT arguments is not supporte=
d on incrementally maintainable materialized view")));
+
+				if (aggref->aggorder !=3D NULL)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("aggregate function with ORDER clause is not supported on i=
ncrementally maintainable materialized view")));
+
+				if (!check_aggregate_supports_ivm(aggref->aggfnoid))
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("aggregate function %s is not supported on incrementally ma=
intainable materialized view", aggname)));
+				break;
+			}
 		default:
 			expression_tree_walker(node, check_ivm_restriction_walker, (void *) con=
text);
 			break;
@@ -1115,6 +1279,46 @@ check_ivm_restriction_walker(Node *node, void *conte=
xt)
 	return false;
 }
=20
+/*
+ * check_aggregate_supports_ivm
+ *
+ * Check if the given aggregate function is supporting IVM
+ */
+static bool
+check_aggregate_supports_ivm(Oid aggfnoid)
+{
+	switch (aggfnoid)
+	{
+		/* count */
+		case F_COUNT_ANY:
+		case F_COUNT_:
+
+		/* sum */
+		case F_SUM_INT8:
+		case F_SUM_INT4:
+		case F_SUM_INT2:
+		case F_SUM_FLOAT4:
+		case F_SUM_FLOAT8:
+		case F_SUM_MONEY:
+		case F_SUM_INTERVAL:
+		case F_SUM_NUMERIC:
+
+		/* avg */
+		case F_AVG_INT8:
+		case F_AVG_INT4:
+		case F_AVG_INT2:
+		case F_AVG_NUMERIC:
+		case F_AVG_FLOAT4:
+		case F_AVG_FLOAT8:
+		case F_AVG_INTERVAL:
+
+			return true;
+
+		default:
+			return false;
+	}
+}
+
 /*
  * CreateIndexOnIMMV
  *
@@ -1172,7 +1376,29 @@ CreateIndexOnIMMV(Query *query, Relation matviewRel)
 	index->concurrent =3D false;
 	index->if_not_exists =3D false;
=20
-	if (query->distinctClause)
+	if (query->groupClause)
+	{
+		/* create unique constraint on GROUP BY expression columns */
+		foreach(lc, query->groupClause)
+		{
+			SortGroupClause *scl =3D (SortGroupClause *) lfirst(lc);
+			TargetEntry *tle =3D get_sortgroupclause_tle(scl, query->targetList);
+			Form_pg_attribute attr =3D TupleDescAttr(matviewRel->rd_att, tle->resno=
 - 1);
+			IndexElem  *iparam;
+
+			iparam =3D makeNode(IndexElem);
+			iparam->name =3D pstrdup(NameStr(attr->attname));
+			iparam->expr =3D NULL;
+			iparam->indexcolname =3D NULL;
+			iparam->collation =3D NIL;
+			iparam->opclass =3D NIL;
+			iparam->opclassopts =3D NIL;
+			iparam->ordering =3D SORTBY_DEFAULT;
+			iparam->nulls_ordering =3D SORTBY_NULLS_DEFAULT;
+			index->indexParams =3D lappend(index->indexParams, iparam);
+		}
+	}
+	else if (query->distinctClause)
 	{
 		/* create unique constraint on all columns */
 		foreach(lc, query->targetList)
@@ -1230,7 +1456,7 @@ CreateIndexOnIMMV(Query *query, Relation matviewRel)
 					(errmsg("could not create an index on materialized view \"%s\" automa=
tically",
 							RelationGetRelationName(matviewRel)),
 					 errdetail("This target list does not have all the primary key column=
s, "
-							   "or this view does not contain DISTINCT clause."),
+							   "or this view does not contain GROUP BY or DISTINCT clause."),
 					 errhint("Create an index on the materialized view for efficient incr=
emental maintenance.")));
 			return;
 		}
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index aa518f20ef..ee41f0007d 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -30,6 +30,7 @@
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "commands/cluster.h"
+#include "commands/defrem.h"
 #include "commands/matview.h"
 #include "commands/tablecmds.h"
 #include "commands/tablespace.h"
@@ -39,6 +40,7 @@
 #include "executor/tstoreReceiver.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/optimizer.h"
 #include "parser/analyze.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_func.h"
@@ -111,6 +113,13 @@ static HTAB *mv_trigger_info =3D NULL;
=20
 static bool in_delta_calculation =3D false;
=20
+/* kind of IVM operation for the view */
+typedef enum
+{
+	IVM_ADD,
+	IVM_SUB
+} IvmOp;
+
 /* ENR name for materialized view delta */
 #define NEW_DELTA_ENRNAME "new_delta"
 #define OLD_DELTA_ENRNAME "old_delta"
@@ -142,7 +151,7 @@ static RangeTblEntry *get_prestate_rte(RangeTblEntry *r=
te, MV_TriggerTable *tabl
 				 QueryEnvironment *queryEnv, Oid matviewid);
 static RangeTblEntry *replace_rte_with_delta(RangeTblEntry *rte, MV_Trigge=
rTable *table, bool is_new,
 		   QueryEnvironment *queryEnv);
-static Query *rewrite_query_for_counting(Query *query, ParseState *pstate);
+static Query *rewrite_query_for_counting_and_aggregates(Query *query, Pars=
eState *pstate);
=20
 static void calc_delta(MV_TriggerTable *table, int rte_index, Query *query,
 			DestReceiver *dest_old, DestReceiver *dest_new,
@@ -153,14 +162,27 @@ static Query *rewrite_query_for_postupdate_state(Quer=
y *query, MV_TriggerTable *
 static void apply_delta(Oid matviewOid, Tuplestorestate *old_tuplestores, =
Tuplestorestate *new_tuplestores,
 			TupleDesc tupdesc_old, TupleDesc tupdesc_new,
 			Query *query, bool use_count, char *count_colname);
+static void append_set_clause_for_count(const char *resname, StringInfo bu=
f_old,
+							StringInfo buf_new,StringInfo aggs_list);
+static void append_set_clause_for_sum(const char *resname, StringInfo buf_=
old,
+						  StringInfo buf_new, StringInfo aggs_list);
+static void append_set_clause_for_avg(const char *resname, StringInfo buf_=
old,
+						  StringInfo buf_new, StringInfo aggs_list,
+						  const char *aggtype);
+static char *get_operation_string(IvmOp op, const char *col, const char *a=
rg1, const char *arg2,
+					 const char* count_col, const char *castType);
+static char *get_null_condition_string(IvmOp op, const char *arg1, const c=
har *arg2,
+						  const char* count_col);
 static void apply_old_delta(const char *matviewname, const char *deltaname=
_old,
 				List *keys);
 static void apply_old_delta_with_count(const char *matviewname, const char=
 *deltaname_old,
-				List *keys, const char *count_colname);
+				List *keys, StringInfo aggs_list, StringInfo aggs_set,
+				const char *count_colname);
 static void apply_new_delta(const char *matviewname, const char *deltaname=
_new,
 				StringInfo target_list);
 static void apply_new_delta_with_count(const char *matviewname, const char=
* deltaname_new,
-				List *keys, StringInfo target_list, const char* count_colname);
+				List *keys, StringInfo target_list, StringInfo aggs_set,
+				const char* count_colname);
 static char *get_matching_condition_string(List *keys);
 static void generate_equal(StringInfo querybuf, Oid opttype,
 			   const char *leftop, const char *rightop);
@@ -1431,11 +1453,44 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
 	 * When a base table is truncated, the view content will be empty if the
 	 * view definition query does not contain an aggregate without a GROUP cl=
ause.
 	 * Therefore, such views can be truncated.
+	 *
+	 * Aggregate views without a GROUP clause always have one row. Therefore,
+	 * if a base table is truncated, the view will not be empty and will cont=
ain
+	 * a row with NULL value (or 0 for count()). So, in this case, we refresh=
 the
+	 * view instead of truncating it.
 	 */
 	if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
 	{
-		ExecuteTruncateGuts(list_make1(matviewRel), list_make1_oid(matviewOid),
-							NIL, DROP_RESTRICT, false, false);
+		if (!(query->hasAggs && query->groupClause =3D=3D NIL))
+			ExecuteTruncateGuts(list_make1(matviewRel), list_make1_oid(matviewOid),
+								NIL, DROP_RESTRICT, false, false);
+		else
+		{
+			Oid			OIDNewHeap;
+			DestReceiver *dest;
+			uint64		processed =3D 0;
+			Query	   *dataQuery =3D rewriteQueryForIMMV(query, NIL);
+			char		relpersistence =3D matviewRel->rd_rel->relpersistence;
+
+			/*
+			 * Create the transient table that will receive the regenerated data. L=
ock
+			 * it against access by any other process until commit (by which time it
+			 * will be gone).
+			 */
+			OIDNewHeap =3D make_new_heap(matviewOid, matviewRel->rd_rel->reltablesp=
ace,
+									   matviewRel->rd_rel->relam,
+									   relpersistence,  ExclusiveLock);
+			LockRelationOid(OIDNewHeap, AccessExclusiveLock);
+			dest =3D CreateTransientRelDestReceiver(OIDNewHeap);
+
+			/* Generate the data */
+			processed =3D refresh_matview_datafill(dest, dataQuery, NULL, NULL, "");
+			refresh_by_heap_swap(matviewOid, OIDNewHeap, relpersistence);
+
+			/* Inform cumulative stats system about our activity */
+			pgstat_count_truncate(matviewRel);
+			pgstat_count_heap_insert(matviewRel, processed);
+		}
=20
 		/* Clean up hash entry and delete tuplestores */
 		clean_up_IVM_hash_entry(entry, false);
@@ -1475,8 +1530,8 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
 	/* Set all tables in the query to pre-update state */
 	rewritten =3D rewrite_query_for_preupdate_state(rewritten, entry->tables,
 												  pstate, matviewOid);
-	/* Rewrite for counting duplicated tuples */
-	rewritten =3D rewrite_query_for_counting(rewritten, pstate);
+	/* Rewrite for counting duplicated tuples and aggregates functions*/
+	rewritten =3D rewrite_query_for_counting_and_aggregates(rewritten, pstate=
);
=20
 	/* Create tuplestores to store view deltas */
 	if (entry->has_old)
@@ -1527,7 +1582,7 @@ IVM_immediate_maintenance(PG_FUNCTION_ARGS)
=20
 			count_colname =3D pstrdup("__ivm_count__");
=20
-			if (query->distinctClause)
+			if (query->hasAggs || query->distinctClause)
 				use_count =3D true;
=20
 			/* calculate delta tables */
@@ -1923,17 +1978,34 @@ replace_rte_with_delta(RangeTblEntry *rte, MV_Trigg=
erTable *table, bool is_new,
 }
=20
 /*
- * rewrite_query_for_counting
+ * rewrite_query_for_counting_and_aggregates
  *
- * Rewrite query for counting duplicated tuples.
+ * Rewrite query for counting duplicated tuples and aggregate functions.
  */
 static Query *
-rewrite_query_for_counting(Query *query, ParseState *pstate)
+rewrite_query_for_counting_and_aggregates(Query *query, ParseState *pstate)
 {
 	TargetEntry *tle_count;
 	FuncCall *fn;
 	Node *node;
=20
+	/* For aggregate views */
+	if (query->hasAggs)
+	{
+		ListCell *lc;
+		List *aggs =3D NIL;
+		AttrNumber next_resno =3D list_length(query->targetList) + 1;
+
+		foreach(lc, query->targetList)
+		{
+			TargetEntry *tle =3D (TargetEntry *) lfirst(lc);
+
+			if (IsA(tle->expr, Aggref))
+				makeIvmAggColumn(pstate, (Aggref *)tle->expr, tle->resname, &next_resn=
o, &aggs);
+		}
+		query->targetList =3D list_concat(query->targetList, aggs);
+	}
+
 	/* Add count(*) for counting distinct tuples in views */
 	fn =3D makeFuncCall(SystemFuncName("count"), NIL, COERCE_EXPLICIT_CALL, -=
1);
 	fn->agg_star =3D true;
@@ -2006,6 +2078,8 @@ rewrite_query_for_postupdate_state(Query *query, MV_T=
riggerTable *table, int rte
 	return query;
 }
=20
+#define IVM_colname(type, col) makeObjectName("__ivm_" type, col, "_")
+
 /*
  * apply_delta
  *
@@ -2019,6 +2093,9 @@ apply_delta(Oid matviewOid, Tuplestorestate *old_tupl=
estores, Tuplestorestate *n
 {
 	StringInfoData querybuf;
 	StringInfoData target_list_buf;
+	StringInfo	aggs_list_buf =3D NULL;
+	StringInfo	aggs_set_old =3D NULL;
+	StringInfo	aggs_set_new =3D NULL;
 	Relation	matviewRel;
 	char	   *matviewname;
 	ListCell	*lc;
@@ -2041,6 +2118,15 @@ apply_delta(Oid matviewOid, Tuplestorestate *old_tup=
lestores, Tuplestorestate *n
 	initStringInfo(&querybuf);
 	initStringInfo(&target_list_buf);
=20
+	if (query->hasAggs)
+	{
+		if (old_tuplestores && tuplestore_tuple_count(old_tuplestores) > 0)
+			aggs_set_old =3D makeStringInfo();
+		if (new_tuplestores && tuplestore_tuple_count(new_tuplestores) > 0)
+			aggs_set_new =3D makeStringInfo();
+		aggs_list_buf =3D makeStringInfo();
+	}
+
 	/* build string of target list */
 	for (i =3D 0; i < matviewRel->rd_att->natts; i++)
 	{
@@ -2057,13 +2143,61 @@ apply_delta(Oid matviewOid, Tuplestorestate *old_tu=
plestores, Tuplestorestate *n
 	{
 		TargetEntry *tle =3D (TargetEntry *) lfirst(lc);
 		Form_pg_attribute attr =3D TupleDescAttr(matviewRel->rd_att, i);
+		char *resname =3D NameStr(attr->attname);
=20
 		i++;
=20
 		if (tle->resjunk)
 			continue;
=20
-		keys =3D lappend(keys, attr);
+		/*
+		 * For views without aggregates, all attributes are used as keys to iden=
tify a
+		 * tuple in a view.
+		 */
+		if (!query->hasAggs)
+			keys =3D lappend(keys, attr);
+
+		/* For views with aggregates, we need to build SET clause for updating a=
ggregate
+		 * values. */
+		if (query->hasAggs && IsA(tle->expr, Aggref))
+		{
+			Aggref *aggref =3D (Aggref *) tle->expr;
+			const char *aggname =3D get_func_name(aggref->aggfnoid);
+
+			/*
+			 * We can use function names here because it is already checked if these
+			 * can be used in IMMV by its OID at the definition time.
+			 */
+
+			/* count */
+			if (!strcmp(aggname, "count"))
+				append_set_clause_for_count(resname, aggs_set_old, aggs_set_new, aggs_=
list_buf);
+
+			/* sum */
+			else if (!strcmp(aggname, "sum"))
+				append_set_clause_for_sum(resname, aggs_set_old, aggs_set_new, aggs_li=
st_buf);
+
+			/* avg */
+			else if (!strcmp(aggname, "avg"))
+				append_set_clause_for_avg(resname, aggs_set_old, aggs_set_new, aggs_li=
st_buf,
+										  format_type_be(aggref->aggtype));
+
+			else
+				elog(ERROR, "unsupported aggregate function: %s", aggname);
+		}
+	}
+
+	/* If we have GROUP BY clause, we use its entries as keys. */
+	if (query->hasAggs && query->groupClause)
+	{
+		foreach (lc, query->groupClause)
+		{
+			SortGroupClause *sgcl =3D (SortGroupClause *) lfirst(lc);
+			TargetEntry		*tle =3D get_sortgroupclause_tle(sgcl, query->targetList);
+			Form_pg_attribute attr =3D TupleDescAttr(matviewRel->rd_att, tle->resno=
 - 1);
+
+			keys =3D lappend(keys, attr);
+		}
 	}
=20
 	/* Start maintaining the materialized view. */
@@ -2094,7 +2228,8 @@ apply_delta(Oid matviewOid, Tuplestorestate *old_tupl=
estores, Tuplestorestate *n
 		if (use_count)
 			/* apply old delta and get rows to be recalculated */
 			apply_old_delta_with_count(matviewname, OLD_DELTA_ENRNAME,
-									   keys, count_colname);
+									   keys, aggs_list_buf, aggs_set_old,
+									   count_colname);
 		else
 			apply_old_delta(matviewname, OLD_DELTA_ENRNAME, keys);
=20
@@ -2120,7 +2255,7 @@ apply_delta(Oid matviewOid, Tuplestorestate *old_tupl=
estores, Tuplestorestate *n
 		/* apply new delta */
 		if (use_count)
 			apply_new_delta_with_count(matviewname, NEW_DELTA_ENRNAME,
-								keys, &target_list_buf, count_colname);
+								keys, aggs_set_new, &target_list_buf, count_colname);
 		else
 			apply_new_delta(matviewname, NEW_DELTA_ENRNAME, &target_list_buf);
 	}
@@ -2135,6 +2270,250 @@ apply_delta(Oid matviewOid, Tuplestorestate *old_tu=
plestores, Tuplestorestate *n
 		elog(ERROR, "SPI_finish failed");
 }
=20
+/*
+ * append_set_clause_for_count
+ *
+ * Append SET clause string for count aggregation to given buffers.
+ * Also, append resnames required for calculating the aggregate value.
+ */
+static void
+append_set_clause_for_count(const char *resname, StringInfo buf_old,
+							StringInfo buf_new,StringInfo aggs_list)
+{
+	/* For tuple deletion */
+	if (buf_old)
+	{
+		/* resname =3D mv.resname - t.resname */
+		appendStringInfo(buf_old,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, resname),
+			get_operation_string(IVM_SUB, resname, "mv", "t", NULL, NULL));
+	}
+	/* For tuple insertion */
+	if (buf_new)
+	{
+		/* resname =3D mv.resname + diff.resname */
+		appendStringInfo(buf_new,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, resname),
+			get_operation_string(IVM_ADD, resname, "mv", "diff", NULL, NULL));
+	}
+
+	appendStringInfo(aggs_list, ", %s",
+		quote_qualified_identifier("diff", resname)
+	);
+}
+
+/*
+ * append_set_clause_for_sum
+ *
+ * Append SET clause string for sum aggregation to given buffers.
+ * Also, append resnames required for calculating the aggregate value.
+ */
+static void
+append_set_clause_for_sum(const char *resname, StringInfo buf_old,
+						  StringInfo buf_new, StringInfo aggs_list)
+{
+	char *count_col =3D IVM_colname("count", resname);
+
+	/* For tuple deletion */
+	if (buf_old)
+	{
+		/* sum =3D mv.sum - t.sum */
+		appendStringInfo(buf_old,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, resname),
+			get_operation_string(IVM_SUB, resname, "mv", "t", count_col, NULL)
+		);
+		/* count =3D mv.count - t.count */
+		appendStringInfo(buf_old,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, count_col),
+			get_operation_string(IVM_SUB, count_col, "mv", "t", NULL, NULL)
+		);
+	}
+	/* For tuple insertion */
+	if (buf_new)
+	{
+		/* sum =3D mv.sum + diff.sum */
+		appendStringInfo(buf_new,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, resname),
+			get_operation_string(IVM_ADD, resname, "mv", "diff", count_col, NULL)
+		);
+		/* count =3D mv.count + diff.count */
+		appendStringInfo(buf_new,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, count_col),
+			get_operation_string(IVM_ADD, count_col, "mv", "diff", NULL, NULL)
+		);
+	}
+
+	appendStringInfo(aggs_list, ", %s, %s",
+		quote_qualified_identifier("diff", resname),
+		quote_qualified_identifier("diff", IVM_colname("count", resname))
+	);
+}
+
+/*
+ * append_set_clause_for_avg
+ *
+ * Append SET clause string for avg aggregation to given buffers.
+ * Also, append resnames required for calculating the aggregate value.
+ */
+static void
+append_set_clause_for_avg(const char *resname, StringInfo buf_old,
+						  StringInfo buf_new, StringInfo aggs_list,
+						  const char *aggtype)
+{
+	char *sum_col =3D IVM_colname("sum", resname);
+	char *count_col =3D IVM_colname("count", resname);
+
+	/* For tuple deletion */
+	if (buf_old)
+	{
+		/* avg =3D (mv.sum - t.sum)::aggtype / (mv.count - t.count) */
+		appendStringInfo(buf_old,
+			", %s =3D %s OPERATOR(pg_catalog./) %s",
+			quote_qualified_identifier(NULL, resname),
+			get_operation_string(IVM_SUB, sum_col, "mv", "t", count_col, aggtype),
+			get_operation_string(IVM_SUB, count_col, "mv", "t", NULL, NULL)
+		);
+		/* sum =3D mv.sum - t.sum */
+		appendStringInfo(buf_old,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, sum_col),
+			get_operation_string(IVM_SUB, sum_col, "mv", "t", count_col, NULL)
+		);
+		/* count =3D mv.count - t.count */
+		appendStringInfo(buf_old,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, count_col),
+			get_operation_string(IVM_SUB, count_col, "mv", "t", NULL, NULL)
+		);
+
+	}
+	/* For tuple insertion */
+	if (buf_new)
+	{
+		/* avg =3D (mv.sum + diff.sum)::aggtype / (mv.count + diff.count) */
+		appendStringInfo(buf_new,
+			", %s =3D %s OPERATOR(pg_catalog./) %s",
+			quote_qualified_identifier(NULL, resname),
+			get_operation_string(IVM_ADD, sum_col, "mv", "diff", count_col, aggtype=
),
+			get_operation_string(IVM_ADD, count_col, "mv", "diff", NULL, NULL)
+		);
+		/* sum =3D mv.sum + diff.sum */
+		appendStringInfo(buf_new,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, sum_col),
+			get_operation_string(IVM_ADD, sum_col, "mv", "diff", count_col, NULL)
+		);
+		/* count =3D mv.count + diff.count */
+		appendStringInfo(buf_new,
+			", %s =3D %s",
+			quote_qualified_identifier(NULL, count_col),
+			get_operation_string(IVM_ADD, count_col, "mv", "diff", NULL, NULL)
+		);
+	}
+
+	appendStringInfo(aggs_list, ", %s, %s, %s",
+		quote_qualified_identifier("diff", resname),
+		quote_qualified_identifier("diff", IVM_colname("sum", resname)),
+		quote_qualified_identifier("diff", IVM_colname("count", resname))
+	);
+}
+
+/*
+ * get_operation_string
+ *
+ * Build a string to calculate the new aggregate values.
+ */
+static char *
+get_operation_string(IvmOp op, const char *col, const char *arg1, const ch=
ar *arg2,
+					 const char* count_col, const char *castType)
+{
+	StringInfoData buf;
+	StringInfoData castString;
+	char   *col1 =3D quote_qualified_identifier(arg1, col);
+	char   *col2 =3D quote_qualified_identifier(arg2, col);
+	char	op_char =3D (op =3D=3D IVM_SUB ? '-' : '+');
+
+	initStringInfo(&buf);
+	initStringInfo(&castString);
+
+	if (castType)
+		appendStringInfo(&castString, "::%s", castType);
+
+	if (!count_col)
+	{
+		/*
+		 * If the attributes don't have count columns then calc the result
+		 * by using the operator simply.
+		 */
+		appendStringInfo(&buf, "(%s OPERATOR(pg_catalog.%c) %s)%s",
+			col1, op_char, col2, castString.data);
+	}
+	else
+	{
+		/*
+		 * If the attributes have count columns then consider the condition
+		 * where the result becomes NULL.
+		 */
+		char *null_cond =3D get_null_condition_string(op, arg1, arg2, count_col);
+
+		appendStringInfo(&buf,
+			"(CASE WHEN %s THEN NULL "
+				"WHEN %s IS NULL THEN %s "
+				"WHEN %s IS NULL THEN %s "
+				"ELSE (%s OPERATOR(pg_catalog.%c) %s)%s END)",
+			null_cond,
+			col1, col2,
+			col2, col1,
+			col1, op_char, col2, castString.data
+		);
+	}
+
+	return buf.data;
+}
+
+/*
+ * get_null_condition_string
+ *
+ * Build a predicate string for CASE clause to check if an aggregate value
+ * will became NULL after the given operation is applied.
+ */
+static char *
+get_null_condition_string(IvmOp op, const char *arg1, const char *arg2,
+						  const char* count_col)
+{
+	StringInfoData null_cond;
+	initStringInfo(&null_cond);
+
+	switch (op)
+	{
+		case IVM_ADD:
+			appendStringInfo(&null_cond,
+				"%s OPERATOR(pg_catalog.=3D) 0 AND %s OPERATOR(pg_catalog.=3D) 0",
+				quote_qualified_identifier(arg1, count_col),
+				quote_qualified_identifier(arg2, count_col)
+			);
+			break;
+		case IVM_SUB:
+			appendStringInfo(&null_cond,
+				"%s OPERATOR(pg_catalog.=3D) %s",
+				quote_qualified_identifier(arg1, count_col),
+				quote_qualified_identifier(arg2, count_col)
+			);
+			break;
+		default:
+			elog(ERROR,"unknown operation");
+	}
+
+	return null_cond.data;
+}
+
+
 /*
  * apply_old_delta_with_count
  *
@@ -2142,13 +2521,20 @@ apply_delta(Oid matviewOid, Tuplestorestate *old_tu=
plestores, Tuplestorestate *n
  * which contains tuples to be deleted from to a materialized view given by
  * matviewname.  This is used when counting is required, that is, the view
  * has aggregate or distinct.
+ *
+ * If the view desn't have aggregates or has GROUP BY, this requires a keys
+ * list to identify a tuple in the view. If the view has aggregates, this
+ * requires strings representing resnames of aggregates and SET clause for
+ * updating aggregate values.
  */
 static void
 apply_old_delta_with_count(const char *matviewname, const char *deltaname_=
old,
-				List *keys, const char *count_colname)
+				List *keys, StringInfo aggs_list, StringInfo aggs_set,
+				const char *count_colname)
 {
 	StringInfoData	querybuf;
 	char   *match_cond;
+	bool	agg_without_groupby =3D (list_length(keys) =3D=3D 0);
=20
 	/* build WHERE condition for searching tuples to be deleted */
 	match_cond =3D get_matching_condition_string(keys);
@@ -2158,22 +2544,26 @@ apply_old_delta_with_count(const char *matviewname,=
 const char *deltaname_old,
 	appendStringInfo(&querybuf,
 					"WITH t AS ("			/* collecting tid of target tuples in the view */
 						"SELECT diff.%s, "			/* count column */
-								"(diff.%s OPERATOR(pg_catalog.=3D) mv.%s) AS for_dlt, "
+								"(diff.%s OPERATOR(pg_catalog.=3D) mv.%s AND %s) AS for_dlt, "
 								"mv.ctid "
+								"%s "				/* aggregate columns */
 						"FROM %s AS mv, %s AS diff "
 						"WHERE %s"					/* tuple matching condition */
 					"), updt AS ("			/* update a tuple if this is not to be deleted */
 						"UPDATE %s AS mv SET %s =3D mv.%s OPERATOR(pg_catalog.-) t.%s "
+											"%s"	/* SET clauses for aggregates */
 						"FROM t WHERE mv.ctid OPERATOR(pg_catalog.=3D) t.ctid AND NOT for_dl=
t "
 					")"
 					/* delete a tuple if this is to be deleted */
 					"DELETE FROM %s AS mv USING t "
 					"WHERE mv.ctid OPERATOR(pg_catalog.=3D) t.ctid AND for_dlt",
 					count_colname,
-					count_colname, count_colname,
+					count_colname, count_colname, (agg_without_groupby ? "false" : "true"=
),
+					(aggs_list !=3D NULL ? aggs_list->data : ""),
 					matviewname, deltaname_old,
 					match_cond,
 					matviewname, count_colname, count_colname, count_colname,
+					(aggs_set !=3D NULL ? aggs_set->data : ""),
 					matviewname);
=20
 	if (SPI_exec(querybuf.data, 0) !=3D SPI_OK_DELETE)
@@ -2237,10 +2627,15 @@ apply_old_delta(const char *matviewname, const char=
 *deltaname_old,
  * matviewname.  This is used when counting is required, that is, the view
  * has aggregate or distinct. Also, when a table in EXISTS sub queries
  * is modified.
+ *
+ * If the view desn't have aggregates or has GROUP BY, this requires a keys
+ * list to identify a tuple in the view. If the view has aggregates, this
+ * requires strings representing SET clause for updating aggregate values.
  */
 static void
 apply_new_delta_with_count(const char *matviewname, const char* deltaname_=
new,
-				List *keys, StringInfo target_list, const char* count_colname)
+				List *keys, StringInfo aggs_set, StringInfo target_list,
+				const char* count_colname)
 {
 	StringInfoData	querybuf;
 	StringInfoData	returning_keys;
@@ -2271,6 +2666,7 @@ apply_new_delta_with_count(const char *matviewname, c=
onst char* deltaname_new,
 	appendStringInfo(&querybuf,
 					"WITH updt AS ("		/* update a tuple if this exists in the view */
 						"UPDATE %s AS mv SET %s =3D mv.%s OPERATOR(pg_catalog.+) diff.%s "
+											"%s "	/* SET clauses for aggregates */
 						"FROM %s AS diff "
 						"WHERE %s "					/* tuple matching condition */
 						"RETURNING %s"				/* returning keys of updated tuples */
@@ -2278,6 +2674,7 @@ apply_new_delta_with_count(const char *matviewname, c=
onst char* deltaname_new,
 						"SELECT %s FROM %s AS diff "
 						"WHERE NOT EXISTS (SELECT 1 FROM updt AS mv WHERE %s);",
 					matviewname, count_colname, count_colname, count_colname,
+					(aggs_set !=3D NULL ? aggs_set->data : ""),
 					deltaname_new,
 					match_cond,
 					returning_keys.data,
diff --git a/src/include/commands/createas.h b/src/include/commands/createa=
s.h
index 76a7873ebf..599bae3b5a 100644
--- a/src/include/commands/createas.h
+++ b/src/include/commands/createas.h
@@ -30,6 +30,7 @@ extern void CreateIvmTriggersOnBaseTables(Query *qry, Oid=
 matviewOid);
 extern void CreateIndexOnIMMV(Query *query, Relation matviewRel);
=20
 extern Query *rewriteQueryForIMMV(Query *query, List *colNames);
+extern void makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *res=
name, AttrNumber *next_resno, List **aggs);
=20
 extern int	GetIntoRelEFlags(IntoClause *intoClause);
=20
--=20
2.25.1


--Multipart=_Mon__28_Aug_2023_11_52_52_+0900_hj6L5h176QaSGtg7
Content-Type: text/x-diff;
 name="v29-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Disposition: attachment;
 filename="v29-0009-Add-support-for-min-max-aggregates-for-IVM.patch"
Content-Transfer-Encoding: 7bit



^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/3] Remove unnecessary volatile qualifiers.
@ 2026-02-18 16:31 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-02-18 16:31 UTC (permalink / raw)

---
 src/backend/replication/syncrep.c     | 19 ++++++++-----------
 src/backend/storage/ipc/procsignal.c  |  4 ++--
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 5 files changed, 14 insertions(+), 17 deletions(-)

diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 7ea6001e9ad..045fd35786a 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -473,7 +473,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -548,19 +547,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -767,8 +766,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -905,7 +903,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -920,7 +917,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 5d33559926a..97791f979ef 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -283,7 +283,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -394,7 +394,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index e1168ad3837..718de1b5e98 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -309,7 +309,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 
 /*
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 579e5933d28..a1ec13d66b9 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -36,7 +36,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -256,7 +256,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index 368e4f3f234..14972f7e7cd 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -50,7 +50,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--J5cpktPts8HkLShw
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment;
	filename=v1-0002-Remove-SpinLockFree-and-S_LOCK_FREE.patch



^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v1 1/1] Remove unnecessary volatile qualifiers.
@ 2026-06-30 21:41 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:41 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers to pg_atomic_* variables or local variables that hold a
value returned by a pg_atomic_* function.  The pointer arguments
for the pg_atomic_* functions are volatile-qualified, so there's no
need to mark the pointer volatile.  Likewise, a local variable that
just holds the result of a pg_atomic_* function gains nothing from
volatile.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
when they were modified inside a PG_TRY block and used afterward,
but the PG_TRY was later removed.
---
 src/backend/access/transam/clog.c     |  2 +-
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  | 10 ++++-----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..47975ba892f 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,7 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
+	PROC_HDR   *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..4acef19e563 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
 {
 	uint64		local_gen;
 	uint64		shared_gen;
-	volatile uint32 flags;
+	uint32		flags;
 
 	Assert(MyProcSignalSlot);
 
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--hE8tq9meMVMcgUcn--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* remove unnecessary volatile qualifiers
@ 2026-06-30 21:47 Nathan Bossart <[email protected]>
  2026-07-06 11:58 ` Re: remove unnecessary volatile qualifiers Heikki Linnakangas <[email protected]>
  0 siblings, 1 reply; 383+ messages in thread

From: Nathan Bossart @ 2026-06-30 21:47 UTC (permalink / raw)
  To: pgsql-hackers

I looked into some of these earlier [0], but ended up leaving them alone at
the time.  Here is a new patch that removes all of the volatile markers in
the tree that seemed obviously unnecessary to me.

[0] https://postgr.es/m/aZX2oUcKf7IzHnnK%40nathan

-- 
nathan


^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* Re: remove unnecessary volatile qualifiers
  2026-06-30 21:47 remove unnecessary volatile qualifiers Nathan Bossart <[email protected]>
@ 2026-07-06 11:58 ` Heikki Linnakangas <[email protected]>
  2026-07-06 15:47   ` Re: remove unnecessary volatile qualifiers Nathan Bossart <[email protected]>
  0 siblings, 1 reply; 383+ messages in thread

From: Heikki Linnakangas @ 2026-07-06 11:58 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; pgsql-hackers

On 01/07/2026 00:47, Nathan Bossart wrote:
> I looked into some of these earlier [0], but ended up leaving them alone at
> the time.  Here is a new patch that removes all of the volatile markers in
> the tree that seemed obviously unnecessary to me.

Thanks!

> --- a/src/backend/access/transam/clog.c
> +++ b/src/backend/access/transam/clog.c
> @@ -450,7 +450,7 @@ static bool
>  TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
>  								XLogRecPtr lsn, int64 pageno)
>  {
> -	volatile PROC_HDR *procglobal = ProcGlobal;
> +	PROC_HDR   *procglobal = ProcGlobal;
>  	PGPROC	   *proc = MyProc;
>  	uint32		nextidx;
>  	uint32		wakeidx;

You might want to get rid of the local variable altogether and just 
refer to ProcGlobal directly..

> @@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
>  {
>  	uint64		local_gen;
>  	uint64		shared_gen;
> -	volatile uint32 flags;
> +	uint32		flags;
>  
>  	Assert(MyProcSignalSlot);
>  

Are you sure about this one? 'flags' is used in the PG_TRY/CATCH block 
that follows. It is modified in the PG_TRY(), here:

> 
> 				/*
> 				 * To avoid an infinite loop, we must always unset the bit in
> 				 * flags.
> 				 */
> 				BARRIER_CLEAR_BIT(flags, type);

and read later in the PG_CATCH() block.


The rest looks OK to me.

- Heikki





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* Re: remove unnecessary volatile qualifiers
  2026-06-30 21:47 remove unnecessary volatile qualifiers Nathan Bossart <[email protected]>
  2026-07-06 11:58 ` Re: remove unnecessary volatile qualifiers Heikki Linnakangas <[email protected]>
@ 2026-07-06 15:47   ` Nathan Bossart <[email protected]>
  2026-07-07 16:03     ` Re: remove unnecessary volatile qualifiers Nathan Bossart <[email protected]>
  0 siblings, 1 reply; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:47 UTC (permalink / raw)
  To: Heikki Linnakangas <[email protected]>; +Cc: pgsql-hackers

On Mon, Jul 06, 2026 at 02:58:12PM +0300, Heikki Linnakangas wrote:
> On 01/07/2026 00:47, Nathan Bossart wrote:
>> I looked into some of these earlier [0], but ended up leaving them alone at
>> the time.  Here is a new patch that removes all of the volatile markers in
>> the tree that seemed obviously unnecessary to me.
> 
> Thanks!

Thanks for reviewing.

>> --- a/src/backend/access/transam/clog.c
>> +++ b/src/backend/access/transam/clog.c
>> @@ -450,7 +450,7 @@ static bool
>>  TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
>>  								XLogRecPtr lsn, int64 pageno)
>>  {
>> -	volatile PROC_HDR *procglobal = ProcGlobal;
>> +	PROC_HDR   *procglobal = ProcGlobal;
>>  	PGPROC	   *proc = MyProc;
>>  	uint32		nextidx;
>>  	uint32		wakeidx;
> 
> You might want to get rid of the local variable altogether and just refer to
> ProcGlobal directly..

Done.

>> @@ -512,7 +512,7 @@ ProcessProcSignalBarrier(void)
>>  {
>>  	uint64		local_gen;
>>  	uint64		shared_gen;
>> -	volatile uint32 flags;
>> +	uint32		flags;
>>  	Assert(MyProcSignalSlot);
> 
> Are you sure about this one? 'flags' is used in the PG_TRY/CATCH block that
> follows. It is modified in the PG_TRY(), here:
> 
>> 
>> 				/*
>> 				 * To avoid an infinite loop, we must always unset the bit in
>> 				 * flags.
>> 				 */
>> 				BARRIER_CLEAR_BIT(flags, type);
> 
> and read later in the PG_CATCH() block.

Whoops.  You are right.  I reverted this part.

-- 
nathan


^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* Re: remove unnecessary volatile qualifiers
  2026-06-30 21:47 remove unnecessary volatile qualifiers Nathan Bossart <[email protected]>
  2026-07-06 11:58 ` Re: remove unnecessary volatile qualifiers Heikki Linnakangas <[email protected]>
  2026-07-06 15:47   ` Re: remove unnecessary volatile qualifiers Nathan Bossart <[email protected]>
@ 2026-07-07 16:03     ` Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-07 16:03 UTC (permalink / raw)
  To: Heikki Linnakangas <[email protected]>; +Cc: pgsql-hackers

Committed.

-- 
nathan






^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 383+ messages in thread

From: Nathan Bossart @ 2026-07-06 15:24 UTC (permalink / raw)

This commit cleans up volatile qualifiers that fit the below
criteria:

* Accesses to shared memory protected by a spinlock or LWLock.
Before commit 0709b7ee72, callers had to use volatile when
accessing spinlock-protected shared memory.  Since spinlock
acquire/release became compiler barriers, and because LWLocks
provide the same guarantee, that is no longer necessary.  These
either predate that change or were cargo-culted from code that did.

* Pointers used only to find the address of a member.  The volatile
qualifier only affects accesses made by dereferencing the pointer,
so it is unnecessary there.

* Accesses to struct members that are marked volatile in the struct
definition.  There's no need to mark these pointers volatile,
either.

* Leftovers from removed PG_TRY blocks.  These were marked volatile
to protect a value that is modified inside a PG_TRY block and used
afterward, but the PG_TRY has since been removed.
---
 src/backend/access/transam/clog.c     |  7 +++---
 src/backend/catalog/index.c           |  2 +-
 src/backend/commands/async.c          |  4 ++--
 src/backend/replication/syncrep.c     | 19 +++++++---------
 src/backend/storage/ipc/procsignal.c  |  8 +++----
 src/backend/storage/ipc/shm_toc.c     | 31 ++++++++++++---------------
 src/backend/storage/lmgr/lock.c       |  2 +-
 src/backend/storage/lmgr/proc.c       |  3 +--
 src/test/modules/test_shm_mq/setup.c  |  4 ++--
 src/test/modules/test_shm_mq/worker.c |  2 +-
 10 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 75012d4b8f0..6f7f6b86eb6 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -450,7 +450,6 @@ static bool
 TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 								XLogRecPtr lsn, int64 pageno)
 {
-	volatile PROC_HDR *procglobal = ProcGlobal;
 	PGPROC	   *proc = MyProc;
 	uint32		nextidx;
 	uint32		wakeidx;
@@ -493,7 +492,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * different from ours.  If another group starts to update a page in the
 	 * same bank as ours, they wait until we release the lock.
 	 */
-	nextidx = pg_atomic_read_u32(&procglobal->clogGroupFirst);
+	nextidx = pg_atomic_read_u32(&ProcGlobal->clogGroupFirst);
 
 	while (true)
 	{
@@ -524,7 +523,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 
 		pg_atomic_write_u32(&proc->clogGroupNext, nextidx);
 
-		if (pg_atomic_compare_exchange_u32(&procglobal->clogGroupFirst,
+		if (pg_atomic_compare_exchange_u32(&ProcGlobal->clogGroupFirst,
 										   &nextidx,
 										   (uint32) MyProcNumber))
 			break;
@@ -576,7 +575,7 @@ TransactionGroupUpdateXidStatus(TransactionId xid, XidStatus status,
 	 * At this point, any processes trying to do this would create a separate
 	 * group.
 	 */
-	nextidx = pg_atomic_exchange_u32(&procglobal->clogGroupFirst,
+	nextidx = pg_atomic_exchange_u32(&ProcGlobal->clogGroupFirst,
 									 INVALID_PROC_NUMBER);
 
 	/* Remember head of list so we can perform wakeups after dropping lock. */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9407c357f27..81bba4beac7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3637,7 +3637,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
 	int			save_sec_context;
 	int			save_nestlevel;
 	IndexInfo  *indexInfo;
-	volatile bool skipped_constraint = false;
+	bool		skipped_constraint = false;
 	PGRUsage	ru0;
 	bool		progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
 	bool		set_tablespace = false;
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index eee8bc29f38..2799f989b96 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -605,7 +605,7 @@ static void CleanupListenersOnExit(void);
 static bool IsListeningOn(const char *channel);
 static void asyncQueueUnregister(void);
 static bool asyncQueueIsFull(void);
-static bool asyncQueueAdvance(volatile QueuePosition *position, int entryLength);
+static bool asyncQueueAdvance(QueuePosition *position, int entryLength);
 static void asyncQueueNotificationToEntry(Notification *n, AsyncQueueEntry *qe);
 static ListCell *asyncQueueAddEntries(ListCell *nextNotify);
 static double asyncQueueUsage(void);
@@ -1968,7 +1968,7 @@ asyncQueueIsFull(void)
  * returns true, else false.
  */
 static bool
-asyncQueueAdvance(volatile QueuePosition *position, int entryLength)
+asyncQueueAdvance(QueuePosition *position, int entryLength)
 {
 	int64		pageno = QUEUE_POS_PAGE(*position);
 	int			offset = QUEUE_POS_OFFSET(*position);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index e0e30579c59..d870f09e0a0 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -483,7 +483,6 @@ SyncRepInitConfig(void)
 void
 SyncRepReleaseWaiters(void)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	XLogRecPtr	writePtr;
 	XLogRecPtr	flushPtr;
 	XLogRecPtr	applyPtr;
@@ -558,19 +557,19 @@ SyncRepReleaseWaiters(void)
 	 * Set the lsn first so that when we wake backends they will release up to
 	 * this location.
 	 */
-	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] < writePtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_WRITE] = writePtr;
 		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] < flushPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_FLUSH] = flushPtr;
 		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
 	}
-	if (walsndctl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
+	if (WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] < applyPtr)
 	{
-		walsndctl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
+		WalSndCtl->lsn[SYNC_REP_WAIT_APPLY] = applyPtr;
 		numapply = SyncRepWakeQueue(false, SYNC_REP_WAIT_APPLY);
 	}
 
@@ -777,8 +776,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 	n = 0;
 	for (i = 0; i < max_wal_senders; i++)
 	{
-		volatile WalSnd *walsnd;	/* Use volatile pointer to prevent code
-									 * rearrangement */
+		WalSnd	   *walsnd;
 		SyncRepStandbyData *stby;
 		WalSndState state;		/* not included in SyncRepStandbyData */
 
@@ -915,7 +913,6 @@ SyncRepGetStandbyPriority(void)
 static int
 SyncRepWakeQueue(bool all, int mode)
 {
-	volatile WalSndCtlData *walsndctl = WalSndCtl;
 	int			numprocs = 0;
 	dlist_mutable_iter iter;
 
@@ -930,7 +927,7 @@ SyncRepWakeQueue(bool all, int mode)
 		/*
 		 * Assume the queue is ordered by LSN
 		 */
-		if (!all && walsndctl->lsn[mode] < proc->waitLSN)
+		if (!all && WalSndCtl->lsn[mode] < proc->waitLSN)
 			return numprocs;
 
 		/*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 1397f65f67b..21a77f98c1d 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -295,7 +295,7 @@ CleanupProcSignalState(int status, Datum arg)
 int
 SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 {
-	volatile ProcSignalSlot *slot;
+	ProcSignalSlot *slot;
 
 	if (procNumber != INVALID_PROC_NUMBER)
 	{
@@ -380,7 +380,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = 0; i < NumProcSignalSlots; i++)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 
 		pg_atomic_fetch_or_u32(&slot->pss_barrierCheckMask, flagbit);
 	}
@@ -406,7 +406,7 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
 	 */
 	for (int i = NumProcSignalSlots - 1; i >= 0; i--)
 	{
-		volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
+		ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
 		pid_t		pid = pg_atomic_read_u32(&slot->pss_pid);
 
 		if (pid != 0)
@@ -670,7 +670,7 @@ ResetProcSignalBarrierBits(uint32 flags)
 static bool
 CheckProcSignal(ProcSignalReason reason)
 {
-	volatile ProcSignalSlot *slot = MyProcSignalSlot;
+	ProcSignalSlot *slot = MyProcSignalSlot;
 
 	if (slot != NULL)
 	{
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 2f9fbb0a519..2217d48c3d9 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -87,7 +87,6 @@ shm_toc_attach(uint64 magic, void *address)
 void *
 shm_toc_allocate(shm_toc *toc, Size nbytes)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -103,9 +102,9 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 		+ allocated_bytes;
 
@@ -117,7 +116,7 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 				(errcode(ERRCODE_OUT_OF_MEMORY),
 				 errmsg("out of shared memory")));
 	}
-	vtoc->toc_allocated_bytes += nbytes;
+	toc->toc_allocated_bytes += nbytes;
 
 	SpinLockRelease(&toc->toc_mutex);
 
@@ -130,16 +129,15 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
 Size
 shm_toc_freespace(shm_toc *toc)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
 	Size		toc_bytes;
 
 	SpinLockAcquire(&toc->toc_mutex);
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 	SpinLockRelease(&toc->toc_mutex);
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
@@ -170,7 +168,6 @@ shm_toc_freespace(shm_toc *toc)
 void
 shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 {
-	volatile shm_toc *vtoc = toc;
 	Size		total_bytes;
 	Size		allocated_bytes;
 	Size		nentry;
@@ -183,14 +180,14 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 
 	SpinLockAcquire(&toc->toc_mutex);
 
-	total_bytes = vtoc->toc_total_bytes;
-	allocated_bytes = vtoc->toc_allocated_bytes;
-	nentry = vtoc->toc_nentry;
+	total_bytes = toc->toc_total_bytes;
+	allocated_bytes = toc->toc_allocated_bytes;
+	nentry = toc->toc_nentry;
 
 #ifdef USE_ASSERT_CHECKING
 	/* Verify no duplicate keys */
 	for (Size i = 0; i < nentry; i++)
-		Assert(vtoc->toc_entry[i].key != key);
+		Assert(toc->toc_entry[i].key != key);
 #endif
 
 	toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
@@ -208,8 +205,8 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	}
 
 	Assert(offset < total_bytes);
-	vtoc->toc_entry[nentry].key = key;
-	vtoc->toc_entry[nentry].offset = offset;
+	toc->toc_entry[nentry].key = key;
+	toc->toc_entry[nentry].offset = offset;
 
 	/*
 	 * By placing a write barrier after filling in the entry and before
@@ -218,7 +215,7 @@ shm_toc_insert(shm_toc *toc, uint64 key, void *address)
 	 */
 	pg_write_barrier();
 
-	vtoc->toc_nentry++;
+	toc->toc_nentry++;
 
 	SpinLockRelease(&toc->toc_mutex);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 8d246ed5a4e..5ee80c7632e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -312,7 +312,7 @@ typedef struct
 	uint32		count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
 } FastPathStrongRelationLockData;
 
-static volatile FastPathStrongRelationLockData *FastPathStrongRelationLocks;
+static FastPathStrongRelationLockData *FastPathStrongRelationLocks;
 
 static void LockManagerShmemRequest(void *arg);
 static void LockManagerShmemInit(void *arg);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7d01c981a1f..87dd289f626 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -660,8 +660,7 @@ InitAuxiliaryProcess(void)
 	}
 
 	/* Mark auxiliary proc as in use by me */
-	/* use volatile pointer to prevent code rearrangement */
-	((volatile PGPROC *) auxproc)->pid = MyProcPid;
+	auxproc->pid = MyProcPid;
 
 	SpinLockRelease(&ProcGlobal->freeProcsLock);
 
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 4f40a61e3d9..991fe27a7fa 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -38,7 +38,7 @@ static worker_state *setup_background_workers(int nworkers,
 											  dsm_segment *seg);
 static void cleanup_background_workers(dsm_segment *seg, Datum arg);
 static void wait_for_workers_to_become_ready(worker_state *wstate,
-											 volatile test_shm_mq_header *hdr);
+											 test_shm_mq_header *hdr);
 static bool check_worker_status(worker_state *wstate);
 
 /* value cached, fetched from shared memory */
@@ -258,7 +258,7 @@ cleanup_background_workers(dsm_segment *seg, Datum arg)
 
 static void
 wait_for_workers_to_become_ready(worker_state *wstate,
-								 volatile test_shm_mq_header *hdr)
+								 test_shm_mq_header *hdr)
 {
 	bool		result = false;
 
diff --git a/src/test/modules/test_shm_mq/worker.c b/src/test/modules/test_shm_mq/worker.c
index e13c05ae5c7..0ba1cfcac47 100644
--- a/src/test/modules/test_shm_mq/worker.c
+++ b/src/test/modules/test_shm_mq/worker.c
@@ -52,7 +52,7 @@ test_shm_mq_main(Datum main_arg)
 	shm_toc    *toc;
 	shm_mq_handle *inqh;
 	shm_mq_handle *outqh;
-	volatile test_shm_mq_header *hdr;
+	test_shm_mq_header *hdr;
 	int			myworkernumber;
 	PGPROC	   *registrant;
 
-- 
2.50.1 (Apple Git-155)


--z39t9WErpHrlykOW--





^ permalink  raw  reply  [nested|flat] 383+ messages in thread


end of thread, other threads:[~2026-07-07 16:03 UTC | newest]

Thread overview: 383+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2023-02-25 21:39 [PATCH v1] WIP: Evaluate arguments of correlated SubPlans in the referencing ExprState Andres Freund <[email protected]>
2023-02-25 21:39 [PATCH v2] WIP: Evaluate arguments of correlated SubPlans in the referencing ExprState Andres Freund <[email protected]>
2023-05-31 11:46 [PATCH v29 08/11] Add aggregates support in IVM Yugo Nagata <[email protected]>
2026-02-18 16:31 [PATCH v1 1/3] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:41 [PATCH v1 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-06-30 21:47 remove unnecessary volatile qualifiers Nathan Bossart <[email protected]>
2026-07-06 11:58 ` Re: remove unnecessary volatile qualifiers Heikki Linnakangas <[email protected]>
2026-07-06 15:47   ` Re: remove unnecessary volatile qualifiers Nathan Bossart <[email protected]>
2026-07-07 16:03     ` Re: remove unnecessary volatile qualifiers Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>
2026-07-06 15:24 [PATCH v2 1/1] Remove unnecessary volatile qualifiers. Nathan Bossart <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox