Easier integration with C++ clients that benefit from "noexcept"

We use FreeRTOS exclusively from C++. One of our mission-critical embedded applications uses C++ exceptions, so we have to consider both the correctness of exception management and the overheads of calling methods that don’t throw C++ exceptions but are not declared ‘noexcept’. Specifically:

  1. If a C++ “noexcept” method calls a function that throws an exception, this will result in termination of the program, which must be avoided. We have an in-house static analysis tool that traces which exceptions each function or constructor might throw, and warns us when a noexcept method might throw. Unfortunately, C methods such as the entry points of FreeRTOS have to be treated as potentially throwing exceptions (because a few C functions can do so), which is problematic even though FreeRTOS never throws C++ exceptions.
  2. If a C++ noexcept function calls a potentially-throwing function, then gcc for ARM creates a small exception table for that function. These tables take up flash memory space, which is in short supply in one of our applications on some target MCUs. Therefore we need to ensure that all non-throwing functions called by our application are declared ‘noexcept’ so that this table is not generated. We can’t do this for FreeRTOS functions that we call unless we add ‘noexcept’ specifiers to all the .h files provided by FreeRTOS that declare functions we call. We would much rather use the FreeRTOS header files as published instead of modified versions.

My request is that in the header files in the FreeRTOS ‘include’ folder that describe public FreeRTOS entry points be annotated using a macro (for example NOEXCEPT) after the parameter list of each function. This macro could have the following default definition in FreeRTOS.h after the line in which FreeRTOSConfig.h is included:

#ifndef NOEXCEPT
# ifdef __cplusplus
#  define NOEXCEPT noexcept
# else
#  define NOEXCEPT
# endif
#endif

This will ensure that NOEXCEPT is ignored when compiling in C mode, but defaults to expanding to noexcept when a client is compiled with a C++ compiler.

1 Like

Sounds good to me. I have been able to avoid exceptions myself, but I can see the problem. One suggestion, the macro name NOEXCEPT is likely not good, as might interact with other uses of the macro by that name, perhaps FREERTOS_NOEXCEPT or taskNOEXCEPT might be more inline with the projects naming convention.

All of the FreeRTOS API functions are already annotated with PRIVILEGED_FUNCTION which currently gets defined to nothing on non-MPU ports. What do you think about the following -

  1. Change the name PRIVILEGED_FUNCTION to something more generic like FUNCTION_ANNOTATOR.
  2. Guard these definitions with #ifndef.
  3. You should then be able to the define FUNCTION_ANNOTATOR in FreeRTOSConfig.h:
    • If you use non-MPU port:
    #define FUNCTION_ANNOTATOR noexcept
    
    • If you use MPU port:
    #define FUNCTION_ANNOTATOR noexcept __attribute__( ( section( "privileged_functions" ) ) )
    

Would this address your problem?

1 Like

the noexcept would need to be conditioned on the header being compiled in C++ mode, just like the extern “C” statement, or it will break for the C compilation.

@richard-damon Assuming that we are talking about my proposal above, noexcept is added by the application in FreeRTOSConfig.h. So the application writer is free to guard them in whatever way they want.

That is, assuming there is a need to add a trailing part of a function declaration to a FreeRTOS function. noexcept is standard C++, so one would expect a config item such as

#define configUSE_NOEXCEPT 0

and later on

#ifdef __cplusplus
# if ( configUSE_NOEXCEPT == 1 )
#  define FREERTOS_NOEXCEPT noexcept
# endif
#endif

Regardless of how this is declared, this config item needs to be guarded by the cplusplus ifdef to prevent C compiler errors.

My point is that currently PRIVILEDGED_FUNCTION isn’t supposed to be a user altered macro, and there is no reason to not add the noexcept decorator when compiling the headers in C++ mode. As far as I know, it only has negative effects if added to the declaration of a function implemented in C++, but user functions do not have that attribute applied to them so the change won’t affect them.

This means that it would make sense to change the definition in mpu_wrappers.h to do that.

It might also make sense to make it conditional so that other attributes could be added if desired, but it seems noexcept could be made standard.

The reason I am less inclined to do that is because it may give an impression that we test in C++ environment with exceptions/no-exceptions which we do not. As you mentioned, the ability to override the decorator still provides people to add any attributes they want.

I guess existence of code indicating testing is a reasonable reason.

@dc42 Does my suggestion above address your usecase?

@aggarg yes it does address my use case. However, I would hesitate to overload the PRIVILEGED_FUNCTION macro in this way because it assumes that all FreeRTOS entry points will be privileged functions, both now and in future. I would prefer a separate macro such as FREERTOS_NOEXCEPT.

Thank you!

Agree and that is why I suggested to use a more generic name like FUNCTION_ANNOTATOR.

I think his concern is that the method assumes that ALL FreeRTOS functions are to be run as “Privileged”, but since that doesn’t mean actually running in privileged mode, just being allowed to switch to that mode, that is likely a fairly safe assumption.

A single macro for function annotations may be problematic when setting multiple annotations.

Also, we would need to be sure our functions can’t throw exceptions by calling a user callback or such.

Except for vPortMalloc, I can’t think of any API functions that call user callbacks. And, since vPortMalloc can be called from situations where there is no enclosing C++ context, the vApplicationMallocHook should not be defined to be able to throw exceptions.

The other case to think of are the trace macros, but again, they are used in contexts that throwing an exception would not be defined, it should be safe to define them as not being allowed to throw exceptions.