esp32: Adds C++ exceptions emergency pool size menuconfig option

This commit is contained in:
Alexey Gerenkov 2017-11-17 12:38:19 +03:00
parent b83792f504
commit 7df96718a2
3 changed files with 80 additions and 6 deletions

14
Kconfig
View File

@ -93,7 +93,7 @@ config OPTIMIZATION_ASSERTIONS_DISABLED
endchoice # assertions
config CXX_EXCEPTIONS
menuconfig CXX_EXCEPTIONS
bool "Enable C++ exceptions"
default n
help
@ -102,8 +102,16 @@ config CXX_EXCEPTIONS
Disabling this option disables C++ exception support in all compiled files, and any libstdc++ code which throws
an exception will abort instead.
Enabling this option currently adds an additional 20KB of heap overhead, and 4KB of additional heap is allocated
the first time an exception is thrown in user code.
Enabling this option currently adds an additional ~500 bytes of heap overhead
when an exception is thrown in user code for the first time.
config CXX_EXCEPTIONS_EMG_POOL_SIZE
int "Emergency Pool Size"
default 0
depends on CXX_EXCEPTIONS
help
Size (in bytes) of the emergency memory pool for C++ exceptions. This pool will be used to allocate
memory for thrown exceptions when there is not enough memory on the heap.
endmenu # Compiler Options

View File

@ -20,7 +20,7 @@ class Base
{
public:
virtual ~Base() {}
virtual void foo() = 0;
virtual void foo() = 0;
};
class Derived : public Base
@ -192,8 +192,13 @@ TEST_CASE("before scheduler has started, static initializers work correctly", "[
TEST_CASE("c++ exceptions work", "[cxx]")
{
/* Note: This test currently trips the memory leak threshold
as libunwind allocates ~4KB of data on first exception. */
/* Note: When first exception (in system) is thrown this test produces memory leaks report (~500 bytes):
- 392 bytes (can vary) as libunwind allocates memory to keep stack frames info to handle exceptions.
This info is kept until global destructors are called by __do_global_dtors_aux()
- 8 bytes are allocated by __cxa_get_globals() to keep __cxa_eh_globals
- 16 bytes are allocated by pthread_setspecific() which is called by __cxa_get_globals() to init TLS var for __cxa_eh_globals
- 88 bytes are allocated by pthread_setspecific() to init internal lock
*/
int thrown_value;
try
{
@ -207,6 +212,60 @@ TEST_CASE("c++ exceptions work", "[cxx]")
printf("OK?\n");
}
TEST_CASE("c++ exceptions emergency pool", "[cxx] [ignore]")
{
/* Note: When first exception (in system) is thrown this test produces memory leaks report (~500 bytes):
- 392 bytes (can vary) as libunwind allocates memory to keep stack frames info to handle exceptions.
This info is kept until global destructors are called by __do_global_dtors_aux()
- 8 bytes are allocated by __cxa_get_globals() to keep __cxa_eh_globals
- 16 bytes are allocated by pthread_setspecific() which is called by __cxa_get_globals() to init TLS var for __cxa_eh_globals
- 88 bytes are allocated by pthread_setspecific() to init internal lock
*/
void **p, **pprev = NULL;
int thrown_value = 0;
// throw first exception to ensure that all initial allocations are made
try
{
throw 33;
}
catch (int e)
{
thrown_value = e;
}
TEST_ASSERT_EQUAL(33, thrown_value);
// consume all dynamic memory
while ((p = (void **)malloc(sizeof(void *)))) {
if (pprev) {
*p = pprev;
} else {
*p = NULL;
}
pprev = p;
}
try
{
throw 20;
}
catch (int e)
{
thrown_value = e;
printf("Got exception %d\n", thrown_value);
}
#if CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE > 0
// free all memory
while (pprev) {
p = (void **)(*pprev);
free(pprev);
pprev = p;
}
TEST_ASSERT_EQUAL(20, thrown_value);
#else
// if emergency pool is disabled we should never get here,
// expect abort() due to lack of memory for new exception
TEST_ASSERT_TRUE(0 == 1);
#endif
}
#endif
/* These test cases pull a lot of code from libstdc++ and are disabled for now

View File

@ -397,6 +397,13 @@ void start_cpu1_default(void)
}
#endif //!CONFIG_FREERTOS_UNICORE
#ifdef CONFIG_CXX_EXCEPTIONS
size_t __cxx_eh_arena_size_get()
{
return CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE;
}
#endif
static void do_global_ctors(void)
{
#ifdef CONFIG_CXX_EXCEPTIONS