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

* [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; 379+ 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] 379+ messages in thread

* [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; 379+ 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] 379+ messages in thread

* [PATCH v12 1/2] Key PGSTAT_KIND_RELATION by relfile locator
@ 2025-10-01 09:45 Bertrand Drouvot <[email protected]>
  0 siblings, 0 replies; 379+ messages in thread

From: Bertrand Drouvot @ 2025-10-01 09:45 UTC (permalink / raw)

This patch changes the key used for the PGSTAT_KIND_RELATION statistic kind.
Instead of the relation oid, it now relies on:

- dboid (linked to RelFileLocator's dbOid)
- objoid which is the result of a new macro (namely RelFileLocatorToPgStatObjid())
that computes an objoid based on the RelFileLocator's spcOid and the
RelFileLocator's relNumber.

This is possible as, since b14e9ce7d55c, the objoid is now uint64 and spcOid
and relNumber are 32 bits.

That will allow us to add new stats (add writes counters) and ensure that some
counters (n_dead_tup and friends) are replicated.

The patch introduces pgstat_reloid_to_relfilelocator() to 1) avoid calling
RelationIdGetRelation() to get the relfilelocator based on the relation oid
and 2) handle the partitioned table case.

Please note that:

- when running pg_stat_have_stats('relation',...) we now need to be connected
to the database that hosts the relation. As pg_stat_have_stats() is not
documented publicly, then the changes done in 029_stats_restart.pl look
enough.

- this patch does not handle rewrites so some tests are failing. It's only
intent is to ease the review and should not be pushed without being
merged with the following patch that handles the rewrites.

- it can be used to test that stats are incremented correctly and that we're
able to retrieve them as long as rewrites are not involved.
---
 src/backend/postmaster/autovacuum.c          |  17 +-
 src/backend/utils/activity/pgstat_relation.c | 236 ++++++++++++++++---
 src/backend/utils/adt/pgstatfuncs.c          |  22 +-
 src/include/catalog/pg_tablespace.dat        |   4 +
 src/include/catalog/pg_tablespace.h          |   8 +
 src/include/pgstat.h                         |  15 +-
 src/include/utils/pgstat_internal.h          |   1 +
 src/test/recovery/t/029_stats_restart.pl     |  40 ++--
 8 files changed, 271 insertions(+), 72 deletions(-)
   6.1% src/backend/postmaster/
  61.6% src/backend/utils/activity/
   5.1% src/backend/utils/adt/
   3.2% src/include/catalog/
   5.6% src/include/
  18.1% src/test/recovery/t/

diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 695e187ba11..5d80e0bd212 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -1991,12 +1991,16 @@ do_autovacuum(void)
 		bool		dovacuum;
 		bool		doanalyze;
 		bool		wraparound;
+		RelFileLocator locator;
 
 		if (classForm->relkind != RELKIND_RELATION &&
 			classForm->relkind != RELKIND_MATVIEW)
 			continue;
 
 		relid = classForm->oid;
+		locator.dbOid = classForm->relisshared ? InvalidOid : MyDatabaseId;
+		locator.spcOid = classForm->reltablespace;
+		locator.relNumber = classForm->relfilenode;
 
 		/*
 		 * Check if it is a temp table (presumably, of some other backend's).
@@ -2025,8 +2029,7 @@ do_autovacuum(void)
 
 		/* Fetch reloptions and the pgstat entry for this table */
 		relopts = extract_autovac_opts(tuple, pg_class_desc);
-		tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
-												  relid);
+		tabentry = pgstat_fetch_stat_tabentry_by_locator(locator);
 
 		/* Check if it needs vacuum or analyze */
 		relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
@@ -2091,6 +2094,7 @@ do_autovacuum(void)
 		bool		dovacuum;
 		bool		doanalyze;
 		bool		wraparound;
+		RelFileLocator locator;
 
 		/*
 		 * We cannot safely process other backends' temp tables, so skip 'em.
@@ -2099,6 +2103,9 @@ do_autovacuum(void)
 			continue;
 
 		relid = classForm->oid;
+		locator.dbOid = classForm->relisshared ? InvalidOid : MyDatabaseId;
+		locator.spcOid = classForm->reltablespace;
+		locator.relNumber = classForm->relfilenode;
 
 		/*
 		 * fetch reloptions -- if this toast table does not have them, try the
@@ -2118,8 +2125,7 @@ do_autovacuum(void)
 		}
 
 		/* Fetch the pgstat entry for this table */
-		tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
-												  relid);
+		tabentry = pgstat_fetch_stat_tabentry_by_locator(locator);
 
 		relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
 								  effective_multixact_freeze_max_age,
@@ -2916,8 +2922,7 @@ recheck_relation_needs_vacanalyze(Oid relid,
 	PgStat_StatTabEntry *tabentry;
 
 	/* fetch the pgstat table entry */
-	tabentry = pgstat_fetch_stat_tabentry_ext(classForm->relisshared,
-											  relid);
+	tabentry = pgstat_fetch_stat_tabentry_ext(relid);
 
 	relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
 							  effective_multixact_freeze_max_age,
diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c
index bc8c43b96aa..89bf0cbed56 100644
--- a/src/backend/utils/activity/pgstat_relation.c
+++ b/src/backend/utils/activity/pgstat_relation.c
@@ -17,12 +17,17 @@
 
 #include "postgres.h"
 
+#include "access/htup_details.h"
 #include "access/twophase_rmgr.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
+#include "catalog/pg_tablespace.h"
+#include "storage/lmgr.h"
 #include "utils/memutils.h"
 #include "utils/pgstat_internal.h"
 #include "utils/rel.h"
+#include "utils/relmapper.h"
+#include "utils/syscache.h"
 #include "utils/timestamp.h"
 
 
@@ -36,13 +41,12 @@ typedef struct TwoPhasePgStatRecord
 	PgStat_Counter inserted_pre_truncdrop;
 	PgStat_Counter updated_pre_truncdrop;
 	PgStat_Counter deleted_pre_truncdrop;
-	Oid			id;				/* table's OID */
-	bool		shared;			/* is it a shared catalog? */
+	RelFileLocator locator;		/* table's rd_locator */
 	bool		truncdropped;	/* was the relation truncated/dropped? */
 } TwoPhasePgStatRecord;
 
 
-static PgStat_TableStatus *pgstat_prep_relation_pending(Oid rel_id, bool isshared);
+static PgStat_TableStatus *pgstat_prep_relation_pending(RelFileLocator locator);
 static void add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_level);
 static void ensure_tabstat_xact_level(PgStat_TableStatus *pgstat_info);
 static void save_truncdrop_counters(PgStat_TableXactStatus *trans, bool is_drop);
@@ -60,8 +64,7 @@ pgstat_copy_relation_stats(Relation dst, Relation src)
 	PgStatShared_Relation *dstshstats;
 	PgStat_EntryRef *dst_ref;
 
-	srcstats = pgstat_fetch_stat_tabentry_ext(src->rd_rel->relisshared,
-											  RelationGetRelid(src));
+	srcstats = pgstat_fetch_stat_tabentry_ext(RelationGetRelid(src));
 	if (!srcstats)
 		return;
 
@@ -94,8 +97,10 @@ pgstat_init_relation(Relation rel)
 
 	/*
 	 * We only count stats for relations with storage and partitioned tables
+	 * and we don't count stats generated during a rewrite.
 	 */
-	if (!RELKIND_HAS_STORAGE(relkind) && relkind != RELKIND_PARTITIONED_TABLE)
+	if ((!RELKIND_HAS_STORAGE(relkind) && relkind != RELKIND_PARTITIONED_TABLE) ||
+		OidIsValid(rel->rd_rel->relrewrite))
 	{
 		rel->pgstat_enabled = false;
 		rel->pgstat_info = NULL;
@@ -130,12 +135,37 @@ pgstat_init_relation(Relation rel)
 void
 pgstat_assoc_relation(Relation rel)
 {
+	RelFileLocator locator;
+
 	Assert(rel->pgstat_enabled);
 	Assert(rel->pgstat_info == NULL);
 
+	/*
+	 * Don't associate stats for relations without storage and non partitioned
+	 * tables.
+	 */
+	if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind) &&
+		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+		return;
+
+	if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+		locator = rel->rd_locator;
+	else
+	{
+		/*
+		 * Partitioned tables don't have storage, so construct a synthetic
+		 * locator for statistics tracking. Use a reserved pseudo tablespace
+		 * OID that cannot conflict with real tablespaces, and the relation
+		 * OID as relNumber. This ensures no collision with regular relations
+		 * even after OID wraparound.
+		 */
+		locator.dbOid = (rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId);
+		locator.spcOid = PSEUDO_PARTITION_TABLE_SPCOID;
+		locator.relNumber = rel->rd_id;
+	}
+
 	/* Else find or make the PgStat_TableStatus entry, and update link */
-	rel->pgstat_info = pgstat_prep_relation_pending(RelationGetRelid(rel),
-													rel->rd_rel->relisshared);
+	rel->pgstat_info = pgstat_prep_relation_pending(locator);
 
 	/* don't allow link a stats to multiple relcache entries */
 	Assert(rel->pgstat_info->relation == NULL);
@@ -167,9 +197,13 @@ pgstat_unlink_relation(Relation rel)
 void
 pgstat_create_relation(Relation rel)
 {
+	/* don't track stats for relations without storage */
+	if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
+		return;
+
 	pgstat_create_transactional(PGSTAT_KIND_RELATION,
-								rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId,
-								RelationGetRelid(rel));
+								rel->rd_locator.dbOid,
+								RelFileLocatorToPgStatObjid(rel->rd_locator));
 }
 
 /*
@@ -181,9 +215,13 @@ pgstat_drop_relation(Relation rel)
 	int			nest_level = GetCurrentTransactionNestLevel();
 	PgStat_TableStatus *pgstat_info;
 
+	/* don't track stats for relations without storage */
+	if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
+		return;
+
 	pgstat_drop_transactional(PGSTAT_KIND_RELATION,
-							  rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId,
-							  RelationGetRelid(rel));
+							  rel->rd_locator.dbOid,
+							  RelFileLocatorToPgStatObjid(rel->rd_locator));
 
 	if (!pgstat_should_count_relation(rel))
 		return;
@@ -213,20 +251,23 @@ pgstat_report_vacuum(Relation rel, PgStat_Counter livetuples,
 	PgStat_EntryRef *entry_ref;
 	PgStatShared_Relation *shtabentry;
 	PgStat_StatTabEntry *tabentry;
-	Oid			dboid = (rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId);
 	TimestampTz ts;
 	PgStat_Counter elapsedtime;
+	RelFileLocator locator;
 
 	if (!pgstat_track_counts)
 		return;
 
+	locator = rel->rd_locator;
+
 	/* Store the data in the table's hash table entry. */
 	ts = GetCurrentTimestamp();
 	elapsedtime = TimestampDifferenceMilliseconds(starttime, ts);
 
 	/* block acquiring lock for the same reason as pgstat_report_autovac() */
-	entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION, dboid,
-											RelationGetRelid(rel), false);
+	entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION, locator.dbOid,
+											RelFileLocatorToPgStatObjid(locator),
+											false);
 
 	shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats;
 	tabentry = &shtabentry->stats;
@@ -285,9 +326,9 @@ pgstat_report_analyze(Relation rel,
 	PgStat_EntryRef *entry_ref;
 	PgStatShared_Relation *shtabentry;
 	PgStat_StatTabEntry *tabentry;
-	Oid			dboid = (rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId);
 	TimestampTz ts;
 	PgStat_Counter elapsedtime;
+	RelFileLocator locator;
 
 	if (!pgstat_track_counts)
 		return;
@@ -325,9 +366,25 @@ pgstat_report_analyze(Relation rel,
 	ts = GetCurrentTimestamp();
 	elapsedtime = TimestampDifferenceMilliseconds(starttime, ts);
 
+	if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+		locator = rel->rd_locator;
+	else
+	{
+		/*
+		 * Partitioned tables don't have storage, so construct a synthetic
+		 * locator for statistics tracking. Use a reserved pseudo tablespace
+		 * OID that cannot conflict with real tablespaces, and the relation
+		 * OID as relNumber. This ensures no collision with regular relations
+		 * even after OID wraparound.
+		 */
+		locator.dbOid = (rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId);
+		locator.spcOid = PSEUDO_PARTITION_TABLE_SPCOID;
+		locator.relNumber = rel->rd_id;
+	}
 	/* block acquiring lock for the same reason as pgstat_report_autovac() */
-	entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION, dboid,
-											RelationGetRelid(rel),
+	entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION,
+											locator.dbOid,
+											RelFileLocatorToPgStatObjid(locator),
 											false);
 	/* can't get dropped while accessed */
 	Assert(entry_ref != NULL && entry_ref->shared_stats != NULL);
@@ -468,7 +525,16 @@ pgstat_update_heap_dead_tuples(Relation rel, int delta)
 PgStat_StatTabEntry *
 pgstat_fetch_stat_tabentry(Oid relid)
 {
-	return pgstat_fetch_stat_tabentry_ext(IsSharedRelation(relid), relid);
+	return pgstat_fetch_stat_tabentry_ext(relid);
+}
+
+PgStat_StatTabEntry *
+pgstat_fetch_stat_tabentry_by_locator(RelFileLocator locator)
+{
+	return (PgStat_StatTabEntry *) pgstat_fetch_entry(
+													  PGSTAT_KIND_RELATION,
+													  locator.dbOid,
+													  RelFileLocatorToPgStatObjid(locator));
 }
 
 /*
@@ -476,12 +542,14 @@ pgstat_fetch_stat_tabentry(Oid relid)
  * whether the to-be-accessed table is a shared relation or not.
  */
 PgStat_StatTabEntry *
-pgstat_fetch_stat_tabentry_ext(bool shared, Oid reloid)
+pgstat_fetch_stat_tabentry_ext(Oid reloid)
 {
-	Oid			dboid = (shared ? InvalidOid : MyDatabaseId);
+	RelFileLocator locator;
 
-	return (PgStat_StatTabEntry *)
-		pgstat_fetch_entry(PGSTAT_KIND_RELATION, dboid, reloid);
+	if (!pgstat_reloid_to_relfilelocator(reloid, &locator))
+		return NULL;
+
+	return pgstat_fetch_stat_tabentry_by_locator(locator);
 }
 
 /*
@@ -503,14 +571,17 @@ find_tabstat_entry(Oid rel_id)
 	PgStat_TableXactStatus *trans;
 	PgStat_TableStatus *tabentry = NULL;
 	PgStat_TableStatus *tablestatus = NULL;
+	RelFileLocator locator;
+
+	if (!pgstat_reloid_to_relfilelocator(rel_id, &locator))
+		return NULL;
+
+	entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_RELATION,
+										   locator.dbOid,
+										   RelFileLocatorToPgStatObjid(locator));
 
-	entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_RELATION, MyDatabaseId, rel_id);
 	if (!entry_ref)
-	{
-		entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_RELATION, InvalidOid, rel_id);
-		if (!entry_ref)
-			return tablestatus;
-	}
+		return tablestatus;
 
 	tabentry = (PgStat_TableStatus *) entry_ref->pending;
 	tablestatus = palloc_object(PgStat_TableStatus);
@@ -706,8 +777,12 @@ AtPrepare_PgStat_Relations(PgStat_SubXactStatus *xact_state)
 		record.inserted_pre_truncdrop = trans->inserted_pre_truncdrop;
 		record.updated_pre_truncdrop = trans->updated_pre_truncdrop;
 		record.deleted_pre_truncdrop = trans->deleted_pre_truncdrop;
-		record.id = tabstat->id;
-		record.shared = tabstat->shared;
+
+		if (tabstat->relation != NULL)
+			record.locator = tabstat->relation->rd_locator;
+		else
+			record.locator = tabstat->locator;
+
 		record.truncdropped = trans->truncdropped;
 
 		RegisterTwoPhaseRecord(TWOPHASE_RM_PGSTAT_ID, 0,
@@ -750,7 +825,7 @@ pgstat_twophase_postcommit(FullTransactionId fxid, uint16 info,
 	PgStat_TableStatus *pgstat_info;
 
 	/* Find or create a tabstat entry for the rel */
-	pgstat_info = pgstat_prep_relation_pending(rec->id, rec->shared);
+	pgstat_info = pgstat_prep_relation_pending(rec->locator);
 
 	/* Same math as in AtEOXact_PgStat, commit case */
 	pgstat_info->counts.tuples_inserted += rec->tuples_inserted;
@@ -785,8 +860,8 @@ pgstat_twophase_postabort(FullTransactionId fxid, uint16 info,
 	TwoPhasePgStatRecord *rec = (TwoPhasePgStatRecord *) recdata;
 	PgStat_TableStatus *pgstat_info;
 
-	/* Find or create a tabstat entry for the rel */
-	pgstat_info = pgstat_prep_relation_pending(rec->id, rec->shared);
+	/* Find or create a tabstat entry for the target locator */
+	pgstat_info = pgstat_prep_relation_pending(rec->locator);
 
 	/* Same math as in AtEOXact_PgStat, abort case */
 	if (rec->truncdropped)
@@ -920,17 +995,21 @@ pgstat_relation_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
  * initialized if not exists.
  */
 static PgStat_TableStatus *
-pgstat_prep_relation_pending(Oid rel_id, bool isshared)
+pgstat_prep_relation_pending(RelFileLocator locator)
 {
 	PgStat_EntryRef *entry_ref;
 	PgStat_TableStatus *pending;
+	uint64		objid;
+
+	objid = RelFileLocatorToPgStatObjid(locator);
 
 	entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_RELATION,
-										  isshared ? InvalidOid : MyDatabaseId,
-										  rel_id, NULL);
+										  locator.dbOid,
+										  objid, NULL);
+
 	pending = entry_ref->pending;
-	pending->id = rel_id;
-	pending->shared = isshared;
+	pending->id = objid;
+	pending->locator = locator;
 
 	return pending;
 }
@@ -1009,3 +1088,82 @@ restore_truncdrop_counters(PgStat_TableXactStatus *trans)
 		trans->tuples_deleted = trans->deleted_pre_truncdrop;
 	}
 }
+
+/*
+ * Convert a relation OID to its corresponding RelFileLocator for statistics
+ * tracking purposes.
+ *
+ * Returns true on success, false if the relation doesn't need statistics
+ * tracking.
+ *
+ * For partitioned tables, constructs a synthetic locator using the relation
+ * OID as relNumber, since they don't have storage.
+ */
+bool
+pgstat_reloid_to_relfilelocator(Oid reloid, RelFileLocator *locator)
+{
+	HeapTuple	tuple;
+	Form_pg_class relform;
+	bool		result = true;
+
+	/* get the relation's tuple from pg_class */
+	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(reloid));
+
+	if (!HeapTupleIsValid(tuple))
+		return false;
+
+	relform = (Form_pg_class) GETSTRUCT(tuple);
+
+	/* skip relations without storage and non partitioned tables */
+	if (!RELKIND_HAS_STORAGE(relform->relkind) &&
+		relform->relkind != RELKIND_PARTITIONED_TABLE)
+	{
+		ReleaseSysCache(tuple);
+		return false;
+	}
+
+	if (relform->relkind != RELKIND_PARTITIONED_TABLE)
+	{
+		/* build the RelFileLocator */
+		locator->relNumber = relform->relfilenode;
+		locator->spcOid = relform->reltablespace;
+
+		/* handle default tablespace */
+		if (!OidIsValid(locator->spcOid))
+			locator->spcOid = MyDatabaseTableSpace;
+
+		/* handle dbOid for global vs local relations */
+		if (locator->spcOid == GLOBALTABLESPACE_OID)
+			locator->dbOid = InvalidOid;
+		else
+			locator->dbOid = MyDatabaseId;
+
+		/* handle mapped relations */
+		if (!RelFileNumberIsValid(locator->relNumber))
+		{
+			locator->relNumber = RelationMapOidToFilenumber(reloid,
+															relform->relisshared);
+			if (!RelFileNumberIsValid(locator->relNumber))
+			{
+				ReleaseSysCache(tuple);
+				return false;
+			}
+		}
+	}
+	else
+	{
+		/*
+		 * Partitioned tables don't have storage, so construct a synthetic
+		 * locator for statistics tracking. Use a reserved pseudo tablespace
+		 * OID that cannot conflict with real tablespaces, and the relation
+		 * OID as relNumber. This ensures no collision with regular relations
+		 * even after OID wraparound.
+		 */
+		locator->dbOid = (relform->relisshared ? InvalidOid : MyDatabaseId);
+		locator->spcOid = PSEUDO_PARTITION_TABLE_SPCOID;
+		locator->relNumber = relform->oid;
+	}
+
+	ReleaseSysCache(tuple);
+	return result;
+}
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 50ea9e8fb83..3f59739de7c 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -23,13 +23,13 @@
 #include "common/ip.h"
 #include "funcapi.h"
 #include "miscadmin.h"
-#include "pgstat.h"
 #include "postmaster/bgworker.h"
 #include "replication/logicallauncher.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/pgstat_internal.h"
 #include "utils/timestamp.h"
 #include "utils/wait_event.h"
 
@@ -1962,9 +1962,14 @@ Datum
 pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
 {
 	Oid			taboid = PG_GETARG_OID(0);
-	Oid			dboid = (IsSharedRelation(taboid) ? InvalidOid : MyDatabaseId);
+	RelFileLocator locator;
 
-	pgstat_reset(PGSTAT_KIND_RELATION, dboid, taboid);
+	/* Get the stats locator from the relation OID */
+	if (!pgstat_reloid_to_relfilelocator(taboid, &locator))
+		PG_RETURN_VOID();
+
+	pgstat_reset(PGSTAT_KIND_RELATION, locator.dbOid,
+				 RelFileLocatorToPgStatObjid(locator));
 
 	PG_RETURN_VOID();
 }
@@ -2318,5 +2323,16 @@ pg_stat_have_stats(PG_FUNCTION_ARGS)
 	uint64		objid = PG_GETARG_INT64(2);
 	PgStat_Kind kind = pgstat_get_kind_from_str(stats_type);
 
+	/* Convert relation OID to relfilenode objid */
+	if (kind == PGSTAT_KIND_RELATION)
+	{
+		RelFileLocator locator;
+
+		if (!pgstat_reloid_to_relfilelocator(objid, &locator))
+			PG_RETURN_BOOL(false);
+
+		objid = RelFileLocatorToPgStatObjid(locator);
+	}
+
 	PG_RETURN_BOOL(pgstat_have_entry(kind, dboid, objid));
 }
diff --git a/src/include/catalog/pg_tablespace.dat b/src/include/catalog/pg_tablespace.dat
index c4cde415219..73ed046be31 100644
--- a/src/include/catalog/pg_tablespace.dat
+++ b/src/include/catalog/pg_tablespace.dat
@@ -10,6 +10,10 @@
 #
 #----------------------------------------------------------------------
 
+/*
+ * When adding a new one, ensure it does not conflict with
+ * PSEUDO_PARTITION_TABLE_SPCOID.
+ */
 [
 
 { oid => '1663', oid_symbol => 'DEFAULTTABLESPACE_OID',
diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h
index 3bd4a74f003..e5e818eb0c5 100644
--- a/src/include/catalog/pg_tablespace.h
+++ b/src/include/catalog/pg_tablespace.h
@@ -21,6 +21,14 @@
 #include "catalog/genbki.h"
 #include "catalog/pg_tablespace_d.h"	/* IWYU pragma: export */
 
+/*
+ * Reserved tablespace OID for partitioned table pseudo locators.
+ * This is not an actual tablespace, just a reserved value to distinguish
+ * partitioned table statistics from regular table statistics. Ensures it does
+ * not conflict with the ones in pg_tablespace.dat.
+ */
+#define PSEUDO_PARTITION_TABLE_SPCOID 1665
+
 /* ----------------
  *		pg_tablespace definition.  cpp turns this into
  *		typedef struct FormData_pg_tablespace
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 216b93492ba..689c624f373 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -15,6 +15,7 @@
 #include "portability/instr_time.h"
 #include "postmaster/pgarch.h"	/* for MAX_XFN_CHARS */
 #include "replication/conflict.h"
+#include "storage/relfilelocator.h"
 #include "utils/backend_progress.h" /* for backward compatibility */	/* IWYU pragma: export */
 #include "utils/backend_status.h"	/* for backward compatibility */	/* IWYU pragma: export */
 #include "utils/pgstat_kind.h"
@@ -38,6 +39,12 @@ typedef struct RelationData *Relation;
 /* Default directory to store temporary statistics data in */
 #define PG_STAT_TMP_DIR		"pg_stat_tmp"
 
+/*
+ * Build a pgstat key Objid based on a RelFileLocator.
+ */
+#define RelFileLocatorToPgStatObjid(locator) \
+	(((uint64) (locator).spcOid << 32) | (locator).relNumber)
+
 /* Values for track_functions GUC variable --- order is significant! */
 typedef enum TrackFunctionsLevel
 {
@@ -178,11 +185,11 @@ typedef struct PgStat_TableCounts
  */
 typedef struct PgStat_TableStatus
 {
-	Oid			id;				/* table's OID */
-	bool		shared;			/* is it a shared catalog? */
+	uint64		id;				/* hash of relfilelocator for stats key */
 	struct PgStat_TableXactStatus *trans;	/* lowest subxact's counts */
 	PgStat_TableCounts counts;	/* event counts to be sent */
 	Relation	relation;		/* rel that is using this entry */
+	RelFileLocator locator;		/* table's relfilelocator */
 } PgStat_TableStatus;
 
 /* ----------
@@ -738,8 +745,8 @@ extern void pgstat_twophase_postabort(FullTransactionId fxid, uint16 info,
 									  void *recdata, uint32 len);
 
 extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
-extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry_ext(bool shared,
-														   Oid reloid);
+extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry_by_locator(RelFileLocator locator);
+extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry_ext(Oid reloid);
 extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id);
 
 
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index 9b8fbae00ed..42f29496551 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -765,6 +765,7 @@ extern void PostPrepare_PgStat_Relations(PgStat_SubXactStatus *xact_state);
 extern bool pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait);
 extern void pgstat_relation_delete_pending_cb(PgStat_EntryRef *entry_ref);
 extern void pgstat_relation_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts);
+extern bool pgstat_reloid_to_relfilelocator(Oid reloid, RelFileLocator *locator);
 
 
 /*
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index cdc427dbc78..4d00087dc6f 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -55,10 +55,10 @@ trigger_funcrel_stat();
 
 # verify stats objects exist
 $sect = "initial";
-is(have_stats('database', $dboid, 0), 't', "$sect: db stats do exist");
-is(have_stats('function', $dboid, $funcoid),
+is(have_stats($connect_db, 'database', $dboid, 0), 't', "$sect: db stats do exist");
+is(have_stats($db_under_test, 'function', $dboid, $funcoid),
 	't', "$sect: function stats do exist");
-is(have_stats('relation', $dboid, $tableoid),
+is(have_stats($db_under_test, 'relation', $dboid, $tableoid),
 	't', "$sect: relation stats do exist");
 
 # regular shutdown
@@ -79,10 +79,10 @@ copy($og_stats, $statsfile) or die "Copy failed: $!";
 $node->start;
 
 $sect = "copy";
-is(have_stats('database', $dboid, 0), 't', "$sect: db stats do exist");
-is(have_stats('function', $dboid, $funcoid),
+is(have_stats($connect_db, 'database', $dboid, 0), 't', "$sect: db stats do exist");
+is(have_stats($db_under_test, 'function', $dboid, $funcoid),
 	't', "$sect: function stats do exist");
-is(have_stats('relation', $dboid, $tableoid),
+is(have_stats($db_under_test, 'relation', $dboid, $tableoid),
 	't', "$sect: relation stats do exist");
 
 $node->stop('immediate');
@@ -96,10 +96,10 @@ $node->start;
 
 # stats should have been discarded
 $sect = "post immediate";
-is(have_stats('database', $dboid, 0), 'f', "$sect: db stats do not exist");
-is(have_stats('function', $dboid, $funcoid),
+is(have_stats($connect_db, 'database', $dboid, 0), 'f', "$sect: db stats do not exist");
+is(have_stats($db_under_test, 'function', $dboid, $funcoid),
 	'f', "$sect: function stats do exist");
-is(have_stats('relation', $dboid, $tableoid),
+is(have_stats($db_under_test, 'relation', $dboid, $tableoid),
 	'f', "$sect: relation stats do not exist");
 
 # get rid of backup statsfile
@@ -110,10 +110,10 @@ unlink $statsfile or die "cannot unlink $statsfile $!";
 trigger_funcrel_stat();
 
 $sect = "post immediate, new";
-is(have_stats('database', $dboid, 0), 't', "$sect: db stats do exist");
-is(have_stats('function', $dboid, $funcoid),
+is(have_stats($connect_db, 'database', $dboid, 0), 't', "$sect: db stats do exist");
+is(have_stats($db_under_test, 'function', $dboid, $funcoid),
 	't', "$sect: function stats do exist");
-is(have_stats('relation', $dboid, $tableoid),
+is(have_stats($db_under_test, 'relation', $dboid, $tableoid),
 	't', "$sect: relation stats do exist");
 
 # regular shutdown
@@ -129,10 +129,10 @@ $node->start;
 
 # no stats present due to invalid stats file
 $sect = "invalid_overwrite";
-is(have_stats('database', $dboid, 0), 'f', "$sect: db stats do not exist");
-is(have_stats('function', $dboid, $funcoid),
+is(have_stats($connect_db, 'database', $dboid, 0), 'f', "$sect: db stats do not exist");
+is(have_stats($db_under_test, 'function', $dboid, $funcoid),
 	'f', "$sect: function stats do not exist");
-is(have_stats('relation', $dboid, $tableoid),
+is(have_stats($db_under_test, 'relation', $dboid, $tableoid),
 	'f', "$sect: relation stats do not exist");
 
 
@@ -145,10 +145,10 @@ append_file($og_stats, "XYZ");
 $node->start;
 
 $sect = "invalid_append";
-is(have_stats('database', $dboid, 0), 'f', "$sect: db stats do not exist");
-is(have_stats('function', $dboid, $funcoid),
+is(have_stats($connect_db, 'database', $dboid, 0), 'f', "$sect: db stats do not exist");
+is(have_stats($db_under_test, 'function', $dboid, $funcoid),
 	'f', "$sect: function stats do not exist");
-is(have_stats('relation', $dboid, $tableoid),
+is(have_stats($db_under_test, 'relation', $dboid, $tableoid),
 	'f', "$sect: relation stats do not exist");
 
 
@@ -307,9 +307,9 @@ sub trigger_funcrel_stat
 
 sub have_stats
 {
-	my ($kind, $dboid, $objid) = @_;
+	my ($db, $kind, $dboid, $objid) = @_;
 
-	return $node->safe_psql($connect_db,
+	return $node->safe_psql($db,
 		"SELECT pg_stat_have_stats('$kind', $dboid, $objid)");
 }
 
-- 
2.34.1


--sdA5zuaL94ts0rne
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v12-0002-handle-relation-statistics-correctly-during-rewr.patch"



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread

* [PATCH v2 1/1] Remove unnecessary volatile qualifiers.
@ 2026-07-06 15:24 Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 379+ 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] 379+ messages in thread


end of thread, other threads:[~2026-07-07 16:03 UTC | newest]

Thread overview: 379+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2023-02-25 21:39 [PATCH v2] WIP: Evaluate arguments of correlated SubPlans in the referencing ExprState Andres Freund <[email protected]>
2023-02-25 21:39 [PATCH v1] WIP: Evaluate arguments of correlated SubPlans in the referencing ExprState Andres Freund <[email protected]>
2025-10-01 09:45 [PATCH v12 1/2] Key PGSTAT_KIND_RELATION by relfile locator Bertrand Drouvot <[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: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]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox