@@ -60,15 +60,9 @@ static void MemoryContextStatsInternal(MemoryContext context, int level);
60
60
* You should not do memory allocations within a critical section, because
61
61
* an out-of-memory error will be escalated to a PANIC. To enforce that
62
62
* 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.
68
63
*/
69
64
#define AssertNotInCriticalSection (context ) \
70
- Assert(CritSectionCount == 0 || (context) == ErrorContext || \
71
- AmCheckpointerProcess())
65
+ Assert(CritSectionCount == 0 || (context)->allowInCritSection)
72
66
73
67
/*****************************************************************************
74
68
* EXPORTED ROUTINES *
@@ -120,7 +114,10 @@ MemoryContextInit(void)
120
114
* require it to contain at least 8K at all times. This is the only case
121
115
* where retained memory in a context is *essential* --- we want to be
122
116
* 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.
124
121
*
125
122
* This should be the last step in this function, as elog.c assumes memory
126
123
* management works once ErrorContext is non-null.
@@ -130,6 +127,7 @@ MemoryContextInit(void)
130
127
8 * 1024 ,
131
128
8 * 1024 ,
132
129
8 * 1024 );
130
+ MemoryContextAllowInCriticalSection (ErrorContext , true);
133
131
}
134
132
135
133
/*
@@ -305,6 +303,26 @@ MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
305
303
}
306
304
}
307
305
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
+
308
326
/*
309
327
* GetMemoryChunkSpace
310
328
* Given a currently-allocated chunk, determine the total space
@@ -533,6 +551,7 @@ MemoryContextCreate(NodeTag tag, Size size,
533
551
MemoryContext node ;
534
552
Size needed = size + strlen (name ) + 1 ;
535
553
554
+ /* creating new memory contexts is not allowed in a critical section */
536
555
Assert (CritSectionCount == 0 );
537
556
538
557
/* Get space for node and name */
@@ -570,6 +589,11 @@ MemoryContextCreate(NodeTag tag, Size size,
570
589
node -> parent = parent ;
571
590
node -> nextchild = parent -> firstchild ;
572
591
parent -> firstchild = node ;
592
+
593
+ #ifdef USE_ASSERT_CHECKING
594
+ /* inherit allowInCritSection flag from parent */
595
+ node -> allowInCritSection = parent -> allowInCritSection ;
596
+ #endif
573
597
}
574
598
575
599
VALGRIND_CREATE_MEMPOOL (node , 0 , false);
0 commit comments