I have not seen any documentation about this, but I have seen some old forum posts about people having problems using exception handling with FreeRTOS which were not much help.
I’m pretty new to c++ (I’m a C guy), so I don’t understand the exception mechanism at a deep enough level to know what is required from the Kernel and/or hardware to support exceptions. I would assume that there is some sort of ISR that needs to be handled, and maybe some sort of task awareness? But frankly I have no idea. Does FreeRTOS do everything that it needs to do in order for exception handling to be enabled? I’m using the A53 core of a Xilinx UltraScale+ if that makes any difference.
C++ exceptions are a software mechanism and not related to processor exceptions or interrupts. Also multi-tasking is not relevant for exceptions.
Hence you should be able to just use it or not.
However, there is a certain price to pay for this feature in terms of code size and memory usage. But you’re probably aware of it.
From what I am personally aware of, FreeRTOS has no specific requirements for exception handling. However, one thing you should be aware of is that because of how the C++ standard is implemented in various compilers, it can actually catch you out when you use the C++ exception mechanism, like in this thread here from a couple of years back (though I think on that specific occasion it might have been due to a compiler bug rather than C++ standard and how its handled). There was another thread from about 6 months ago or so (not something I can immediately find for reference, will link it as soon as I find it - perhaps others will also remember it and beat me to linking to it if I dont find it by then) where this subject was touched on when compilers can catch you out with the use of C++ exceptions in FreeRTOS.
Ilya
EDIT: ah yes, it is this thread here - it does mentions the fact that you should be very weary of using exceptions for the reason I mentioned but it also mentions a few other issues you should be aware of
The posts you linked are partially what prompted me to ask this question in the first place, because it was not clear to me if it was safe to use exceptions or not. I am not concerned about resource usage in the slightest (we have WAY more than we could ever use), and our tasks are written in such a way that a failure of one will not kill the system (i.e the health task dying won’t interfere with system operation), so I didn’t think the advice in the second thread was very relevant.
My specific situation is that I had written a constructor which could throw an exception if invalid arguments were passed. (Specifically a c++ wrapper for FreeRTOS tasks that rejected a name longer than configMAX_TASK_NAME_LEN). Someone made a static instance of Task() and passed in a name that was too long. So the exception was thrown before main() had been called since this was done during static initialization, or whatever c++ calls it.
What I expected to happen was that we would somehow end up in vApplicationAssert, and a stack trace would show it came via an exception. But what actually happened was that the debugger disconnected before main() could execute, and would not reconnect. So we had no idea what happened.
In hindsight it was a bad idea to throw an exception in the constructor (consider that lesson learned…) , but it got me wondering what was SUPPOSED to happen to unhandled execptions. Apparently on a general-purpose system, it would just crash the program and the OS handles cleanup. But this is embedded, so it got me wondering if it was okay to use exceptions at all.
My current thoughts are that we should disable them, because they seem unpredictable. But honestly I don’t really want to because it sure would be nice to avoid all the if(error) checks.
One thing I will say straight off the bat (others may join me in my request for the same reasons): I would appreciate a little background into what sort of FreeRTOS based application/project. Mainly because it would give me an idea of where the potential bottlenecks of your application and whether they will actually cause you the greave down the line.
One potential issue that I can see (and that wasnt perhaps clearly indicated in one of the threads I linked to) is how the exception handling scheme used by a compiler you are using will affect your threads that are still running - I believe some compilers may invoke/start dragging in other exceptions that may be needed to be handled. This would have the consequence that even if the dead task/thread wasnt tightly coupled to others, the need for exception handling would introduce a lot of delays (at least potentially) and it would just render your deterministic (and for any RTOS based, not just FreeRTOS, deterministic behaviour is one of the main goals why an rtos is chosen to begin with) system useless. It would also mean that even if you have plenty of memory resources, theres no guarantee that the compiler wouldnt eat up the memory a task is using just because of its scheme to handle exceptions. That would just make the situation even worse and your application even less deterministic.
Hope that at least starts to explain the difficulties with using exceptions
This reminds me of a quote from “Tango & Cash”: “Cash, use extreme caution! - Yes, Mommy!”
On a more serious note, however, theres nothing stopping you from trying to use them in your application for debugging purposes - but as you quite rightly point out: this is embedded, so the stuff that wouldnt bite you in the ass in the traditional applications could well bite you quite painfully in the ass here if you aint careful
The two issues you raise are fairly relevant to the discussion - if your tasks are indeed independent enough of each other AND resource usage is not an issue, why not consider using language supprted SEH?
There is more to the discussion, though. Do you really believe that SEH will help you isolate tasks against each other and help build more overall stable systems? I do not have a final answer to that, but I can point out numerous cases where that will not be the case.
At the heart of the issue is the fact that FreeRTOS does not generally support MMUs (ie disjoint address spaces). One corollary of that is that faulty application code may (and will, and time has proven again and again) overtrample system data structures such as PCB chains. It happens all the time. Once that happens, you have a system wide crash that the OS can not recover from. Also, physical crashes (faults) frequently happen long after the true error has occurred, so if, say, task A crashes, the root cause may have been overtrampling of memory by task B many many cycles prior. So what have you gained in this scenario from “gracefully recovering” (whatever that means) from a fault in task A?
Don’t get me wrong, I am not generally opposed to attempting to write good and stable systems, but I do not believe that this one screw to turn (SEH) will alone and withouth the help of others (such as MMU support) work towards that goal.
Unfortunately I cant’t lookup my GCC/newlib based code at the moment, but I think I’ve just implemented abort() which is finally called on abnormal program termination also on bare metal applications like FreeRTOS apps. This overrides the (weak) built-in function and there you could call e.g. your vApplicationAssert function and/or you can put a breakpoint at it to get a call stack. I think this could work even when throwing in a constructor (bad) of a global/static object (even worse)
@shtirka, I would love to expand on the details of my application, but its unfortunately not something I can disclose. I can say that its primary function is to be a closed-loop control system, it works in tandem with the FPGA side of the UltraScale, and that its a subcomponent of a larger system.
So that being said, having exceptions impact other tasks is a huge concern to me, as our control loop needs to be very deterministic in its timing. If a nonvolatile write fails and we get an exception in the logger task, that cannot prevent the control loop from functioning.
What you seem to be implying is that the act of handling an exception could lead to the scheduler not respecting task priority by continuing to handle an exception in a low priority task rather than switching to a higher priority task. Is that really something that could happen? In my mind, in order to prevent tasks from switching you would have to either disable interrupts or the scheduler would need to be aware of the exception mechanism - neither of which I think can happen because the c++ runtime would need to cooperate with FreeRTOS in order to do so, and its been stated that FreeRTOS does not do anything special to support c++.
What does seem more likely is that the exception handler would trample or exhaust task memory - but if c++ allowed exceptions to trample task memory, wouldn’t that defeat the purpose of exception handling in the first place? Or maybe I am misunderstanding something?
@RAc, you bring up a good point on how much value SEH really provides without an MMU. I was thinking that exceptions would be used for non-catastrophic errors, such as invalid sensor data or a failed nonvolatile write, which aren’t really at risk of memory trampling. This can obviously be implemented without exceptions, but I was hoping it could reduce boilerplate error handling code. Is this a bad approach? I’m fairly new to c++, so I don’t really know the do’s and don’ts .
I’d like to thank everyone for their input - I didn’t expect such a large response!
It seems to me that the consensus here is to avoid SEH on embedded systems for various reasons, and frankly I’m not sure its worth the risk to find out if it would be of any benefit to our application. If you disagree, I’d love to be convinced otherwise!
Throwing and catching an exception (in a task) is just software. So it shouldn’t directly affect other tasks.
However, if you don’t want to deal with if - wedges for longer code sequences,
an enclosing DWF (do {} while (false);) could mitigate that. On error store the error (ID) and break, handle the errors afterwards.
As usual in engineering, it is imprtant to weigh costs against gain. In all customer scenarions I have come across, costs outweighed gain, but that is by no means always the case.
One thing I find particularly awkward to deal with when it comes to C++ native SEH (as outlined in the thread I linked) is that the run time system creates several memory sections without really telling you what they are and how to deal with them. Even if you have enough memory available, you will still need to consider them in your overall memory layout scheme (linker command file) to ensure that they do not interfere with your architecture (that can include subtle use cases such as where you temprorarily store images for a firmware update).
But again, it is up to you to decide whether it is worth a try. You publishing your results is very much appreciated by the community…
Its not a problem if you cant disclose much - it just would have been nice to have this info for the sake of context to see where any potential bottlenecks are and how tightly coupled the system and any of the subsystems are.
Onto the main topic then. My biggest concern is how the mechanism of compiler itself treating the C++ exceptions will impact individual tasks (it doesnt impact scheduling mechanism as such - at least not directly) and whether they (or any tasks depending on it) will deliver within the time scale they are supposed to as per requirements you have for the system. This will absolutely be an issue when you have either a very tightly coupled or a very time sensitive system where deterministic and predictable behaviour is everything - which doesnt sound like you have. So at least in theory you could get away with using exceptions - but as it stands its not something I would absolutely 150% guarantee simply because of how various compilers (and even different versions of a single compiler) treat and implement the C++ standard (thats where the main deal breaker is really).
Oh there absolutely is a point in having some sort of error handling implemented - the big question for me personally is whether the exception handling is the way to go and so this decision needs to be taken on a clear head so to speak because you have to consider how tightly coupled and how time sensitive your system and your application is.