aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/mmgr/mcxt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/mmgr/mcxt.c')
-rw-r--r--src/backend/utils/mmgr/mcxt.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index e83e76dc0f3..4185a03e9ff 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -60,15 +60,9 @@ static void MemoryContextStatsInternal(MemoryContext context, int level);
* You should not do memory allocations within a critical section, because
* an out-of-memory error will be escalated to a PANIC. To enforce that
* rule, the allocation functions Assert that.
- *
- * There are a two exceptions: 1) error recovery uses ErrorContext, which
- * has some memory set aside so that you don't run out. And 2) checkpointer
- * currently just hopes for the best, which is wrong and ought to be fixed,
- * but it's a known issue so let's not complain about in the meanwhile.
*/
#define AssertNotInCriticalSection(context) \
- Assert(CritSectionCount == 0 || (context) == ErrorContext || \
- AmCheckpointerProcess())
+ Assert(CritSectionCount == 0 || (context)->allowInCritSection)
/*****************************************************************************
* EXPORTED ROUTINES *
@@ -120,7 +114,10 @@ MemoryContextInit(void)
* require it to contain at least 8K at all times. This is the only case
* where retained memory in a context is *essential* --- we want to be
* sure ErrorContext still has some memory even if we've run out
- * elsewhere!
+ * elsewhere! Also, allow allocations in ErrorContext within a critical
+ * section. Otherwise a PANIC will cause an assertion failure in the
+ * error reporting code, before printing out the real cause of the
+ * failure.
*
* This should be the last step in this function, as elog.c assumes memory
* management works once ErrorContext is non-null.
@@ -130,6 +127,7 @@ MemoryContextInit(void)
8 * 1024,
8 * 1024,
8 * 1024);
+ MemoryContextAllowInCriticalSection(ErrorContext, true);
}
/*
@@ -306,6 +304,26 @@ MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
}
/*
+ * MemoryContextAllowInCriticalSection
+ * Allow/disallow allocations in this memory context within a critical
+ * section.
+ *
+ * Normally, memory allocations are not allowed within a critical section,
+ * because a failure would lead to PANIC. There are a few exceptions to
+ * that, like allocations related to debugging code that is not supposed to
+ * be enabled in production. This function can be used to exempt specific
+ * memory contexts from the assertion in palloc().
+ */
+void
+MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
+{
+ AssertArg(MemoryContextIsValid(context));
+#ifdef USE_ASSERT_CHECKING
+ context->allowInCritSection = allow;
+#endif
+}
+
+/*
* GetMemoryChunkSpace
* Given a currently-allocated chunk, determine the total space
* it occupies (including all memory-allocation overhead).
@@ -533,6 +551,7 @@ MemoryContextCreate(NodeTag tag, Size size,
MemoryContext node;
Size needed = size + strlen(name) + 1;
+ /* creating new memory contexts is not allowed in a critical section */
Assert(CritSectionCount == 0);
/* Get space for node and name */
@@ -570,6 +589,11 @@ MemoryContextCreate(NodeTag tag, Size size,
node->parent = parent;
node->nextchild = parent->firstchild;
parent->firstchild = node;
+
+#ifdef USE_ASSERT_CHECKING
+ /* inherit allowInCritSection flag from parent */
+ node->allowInCritSection = parent->allowInCritSection;
+#endif
}
VALGRIND_CREATE_MEMPOOL(node, 0, false);