@@ -60,15 +60,9 @@ static void MemoryContextStatsInternal(MemoryContext context, int level);
6060 * You should not do memory allocations within a critical section, because
6161 * an out-of-memory error will be escalated to a PANIC. To enforce that
6262 * rule, the allocation functions Assert that.
63- *
64- * There are a two exceptions: 1) error recovery uses ErrorContext, which
65- * has some memory set aside so that you don't run out. And 2) checkpointer
66- * currently just hopes for the best, which is wrong and ought to be fixed,
67- * but it's a known issue so let's not complain about in the meanwhile.
6863 */
6964#define AssertNotInCriticalSection (context ) \
70- Assert(CritSectionCount == 0 || (context) == ErrorContext || \
71- AmCheckpointerProcess())
65+ Assert(CritSectionCount == 0 || (context)->allowInCritSection)
7266
7367/*****************************************************************************
7468 * EXPORTED ROUTINES *
@@ -120,7 +114,10 @@ MemoryContextInit(void)
120114 * require it to contain at least 8K at all times. This is the only case
121115 * where retained memory in a context is *essential* --- we want to be
122116 * sure ErrorContext still has some memory even if we've run out
123- * elsewhere!
117+ * elsewhere! Also, allow allocations in ErrorContext within a critical
118+ * section. Otherwise a PANIC will cause an assertion failure in the
119+ * error reporting code, before printing out the real cause of the
120+ * failure.
124121 *
125122 * This should be the last step in this function, as elog.c assumes memory
126123 * management works once ErrorContext is non-null.
@@ -130,6 +127,7 @@ MemoryContextInit(void)
130127 8 * 1024 ,
131128 8 * 1024 ,
132129 8 * 1024 );
130+ MemoryContextAllowInCriticalSection (ErrorContext , true);
133131}
134132
135133/*
@@ -305,6 +303,26 @@ MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
305303 }
306304}
307305
306+ /*
307+ * MemoryContextAllowInCriticalSection
308+ * Allow/disallow allocations in this memory context within a critical
309+ * section.
310+ *
311+ * Normally, memory allocations are not allowed within a critical section,
312+ * because a failure would lead to PANIC. There are a few exceptions to
313+ * that, like allocations related to debugging code that is not supposed to
314+ * be enabled in production. This function can be used to exempt specific
315+ * memory contexts from the assertion in palloc().
316+ */
317+ void
318+ MemoryContextAllowInCriticalSection (MemoryContext context , bool allow )
319+ {
320+ AssertArg (MemoryContextIsValid (context ));
321+ #ifdef USE_ASSERT_CHECKING
322+ context -> allowInCritSection = allow ;
323+ #endif
324+ }
325+
308326/*
309327 * GetMemoryChunkSpace
310328 * Given a currently-allocated chunk, determine the total space
@@ -533,6 +551,7 @@ MemoryContextCreate(NodeTag tag, Size size,
533551 MemoryContext node ;
534552 Size needed = size + strlen (name ) + 1 ;
535553
554+ /* creating new memory contexts is not allowed in a critical section */
536555 Assert (CritSectionCount == 0 );
537556
538557 /* Get space for node and name */
@@ -570,6 +589,11 @@ MemoryContextCreate(NodeTag tag, Size size,
570589 node -> parent = parent ;
571590 node -> nextchild = parent -> firstchild ;
572591 parent -> firstchild = node ;
592+
593+ #ifdef USE_ASSERT_CHECKING
594+ /* inherit allowInCritSection flag from parent */
595+ node -> allowInCritSection = parent -> allowInCritSection ;
596+ #endif
573597 }
574598
575599 VALGRIND_CREATE_MEMPOOL (node , 0 , false);
0 commit comments