We have a large(ish) real-time embedded system. It's VxWorks, if that makes any difference. It has some C code in DKMs, but is 95%+ in C++.
It has absolutely no exception handling, nor Posix signal handling. It is multi-threaded, so if one thread/process/subsystem dereferences a null pointer, or access a non-existent vector entry, etc, I guess that it just dies(?) and the rest of the system ... limps along without it?
We need a robust mechanism to handle such anomalies and keep the system running smoothly, unattenuated, without human intervention.
Here are my first, somewhat jumbled, thoughts, and I would appreciate any comments on whether this is too simple, too complex, missing something, etc. I am sure that this is industry standard and that there are accepted best engineering practises. What are they?
For the C code, I plan to add a signal handler to catch segmentation faults, etc. It would be too much effort to add meaningful exception handling to the C++ code, so I had thought a single try/catch around the main()
function. However, while those can log & swallow "a bad thing happened", I am not certain that they can identify the offending software and "make it better", and it seems a bit heavy-handed to restart everything, rather than just the offender.
Perhaps (the above combined with) a watchdog or heartbeat mechanism?
A watchdog in main()
could know the process Id of each thread, since it started them, and periodically check their status, killing and restarting any which are hanging or have died.
Or a heartbeat mechanism, where the main()
periodically sends a message to each thread and start a timer. If the timer expires before an ACK is received, kill & restart the thread (I use the term thread loosely; they might be processes).
The above sounds sort of vague, but is perhaps a reasonable start. What is a good design, preferably one used often in similar circumstances?
[Update] After investigation, I find that our C++ code builds on a framework, which we cannot alter, and which runs everything as threads, nor processes.
My latest proposal is that we:
- handle errors in the C code by signal handler (whether one or one per DKM, if these are processes)
- add a single try/catch around the
main
function- both of the above will log the problem to a disk file with as much diagnostic information as possible and "somehow" restart all of the software (as opposed to individual threads)
- when the system starts up, it will launch a watchdog process. This process will launch the application as a single process and monitor it at regular intervals. If it cannot be found, or is "stuck", then it will be (killed and) restarted.
I do not see much point in complicating the watchdog process, which must be robust and should never fail. To that end, I am not sure of the advisability of a heartbeat or handshake keep-alive mechanism. If we, then I would imagine a single interchange between the watchdog process and the application process, but that would only be meaningful if the the application process had a similar monitor/handshake mechanism with each of its threads.
I will put that to the powers that be and see just how much robustness they wants and how much effort they are willing to invest. If it helps anyone to comment, this is a DAL D project, so not overly critical.