Project 7.09 Section 7 ⚡ Embedded Relevance: High throw; Exception Slicing RTOS Fault Escalation NVRAM Logging

7.09 Nested try-catch, Exception Slicing during Rethrow & RTOS Fault Escalation

Executive Summary: Examining multi-layered exception handling and exception rethrowing with throw;. We contrast standard C++ exception propagation with real-time RTOS fault escalation architectures, where task-level errors are escalated to supervisors, safe mode, or persistent NVRAM black-box logging.

💻 1. Annotated Source Code

#include <iostream>
#include <stdexcept>
using namespace std;

void processPositive(int num);
void doSomething(int num);

int main() {

	int input;

	try {
		cout << "Enter a number to process!" << endl;
		cin >> input;

		doSomething(input);
		cout << "Yay!  main was able to completely process the num!" << endl;
	}
	catch (const invalid_argument& err) {
		cout << "main says there is an error!" << endl;
		cout << err.what() << endl;
	}
	catch (const out_of_range& err) {
		cout << "main says the number is too big!" << endl;
		cout << err.what() << endl;
	}

	return 0;
}


void processPositive(int num) {
	cout << "Welcome to the positive integer processor!" << endl;

	if (num > 100) {
		cout << "processPositive says the number is too big!" << endl;
		throw out_of_range("Number cannot be greater than 100");
	}
	else if (num >= 0) {
		cout << "Good job!  You passed in a positive num to processPositive!" << endl;
	}
	else {
		throw invalid_argument("Negative number passed in!");
	}
}

void doSomething(int num) {
	try {
		processPositive(num);
		cout << "Yay!  doSomething could process the num!" << endl;
	}
	catch (const invalid_argument& err) {
		cout << "doSomething says there is a problem!" << endl;
		throw;
	}
	catch (const out_of_range& err) {
		cout << "doSomething says the number is too big!" << endl;
		throw;
	}
}

📐 2. Architecture & UML Class Model

📐 Exception Rethrow (throw;) & Stack Unwinding Mechanics
+ Public - Private # Protected
<<compilation-unit>> ExceptionRethrowModule Stack Unwinder
(none / stateless)
+processAction() : void[rethrows via throw;]
+topLevelHandler() : void

📚 3. Core C++ Concepts Deep-Dive

1. Correct Rethrowing Syntax (throw; vs throw e;)

When rethrowing an active exception, always use throw; with no operand. Using throw e; constructs a new exception copy of type e, causing object slicing if e is a base class reference.

2. Multi-Tier Error Propagation

A low-level function catches an error to perform localized cleanup (e.g. closing a file or releasing a lock), and then rethrows it to let higher-level orchestration logic handle user notification or system recovery.

⚡ 4. Embedded Systems & Hardware Reality

1. RTOS Hierarchical Fault Escalation

In multi-tasking Real-Time Operating Systems (e.g. FreeRTOS, Zephyr), errors escalate through formal levels:

  • Level 1 (Task Level): Retry transient peripheral read (e.g. I2C retry).
  • Level 2 (Supervisor Level): Restart malfunctioning task and re-initialize peripheral driver.
  • Level 3 (System Level): Log error telemetry to Non-Volatile Backup SRAM (NVRAM) and trigger a controlled software reset via NVIC.

2. Non-Volatile Black-Box Logging

Safety-critical firmware maintains a circular crash log in battery-backed SRAM or EEPROM to preserve stack frames and fault status registers across watchdog resets for forensic diagnosis.

💡 5. Production-Ready Embedded Refactoring

Here is an embedded multi-tier fault escalation and telemetry logging architecture:

💡 Production-Ready Refactor
#include <cstdint>

enum class EscalationLevel : uint8_t {
    TaskHandled = 0,
    TaskRestart,
    SystemResetSafeMode
};

struct FaultLogEntry {
    uint32_t timestamp_ms;
    uint16_t error_code;
    uint8_t  task_id;
    uint8_t  severity;
};

class SystemFaultSupervisor {
public:
    static EscalationLevel record_fault(uint8_t task_id, uint16_t error_code, uint8_t retries_exhausted) noexcept {
        // 1. Write to Non-Volatile Backup SRAM
        log_to_nvram({/* timestamp */ 123456, error_code, task_id, retries_exhausted});

        // 2. Determine escalation tier
        if (retries_exhausted < 3) {
            return EscalationLevel::TaskHandled;
        } else if (retries_exhausted < 5) {
            return EscalationLevel::TaskRestart;
        } else {
            // Escalate to controlled MCU Reset
            trigger_system_reset();
            return EscalationLevel::SystemResetSafeMode;
        }
    }

private:
    static void log_to_nvram(const FaultLogEntry& entry) noexcept {
        // Write to battery-backed register bank
    }
    static void trigger_system_reset() noexcept {
        // NVIC_SystemReset(); (ARM Cortex-M CMSIS call)
    }
};

📝 Knowledge Verification Quiz

Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.

Q1. What is the critical difference between 'throw;' and 'throw e;' in a C++ catch block?
A 'throw;' rethrows the exact original polymorphic exception object, while 'throw e;' makes a copy and causes object slicing
B 'throw;' creates a new memory allocation
C 'throw e;' is faster because it bypasses the compiler
D 'throw;' cannot be used inside nested catch blocks
Detailed Explanation: throw; re-raises the active exception retaining its dynamic polymorphic type. throw e; copies the base-type slice, slicing away any derived class data and custom what() logic.
Q2. In an RTOS architecture, what is the primary role of a Supervisor Task?
A To monitor worker task heartbeats, handle unrecoverable task errors, and execute restart or fail-safe protocols
B To compile C++ code at runtime
C To allocate dynamic heap memory for all threads
D To format SD card file systems on boot
Detailed Explanation: Supervisor tasks monitor thread health (via watchdog check-ins) and coordinate fault recovery (such as restarting crashed worker tasks or commanding safe shutdowns).
Q3. Why is Non-Volatile RAM (NVRAM / Backup SRAM) preferred over regular SRAM for crash telemetry logging?
A NVRAM retains its data across CPU resets and power loss, allowing crash diagnostics after system reboot
B NVRAM executes code 10x faster than cache
C NVRAM has infinite storage capacity
D NVRAM does not require address lines
Detailed Explanation: Backup SRAM or battery-backed registers maintain state through hardware watchdog resets and power cycles, enabling post-mortem crash analysis.
Q4. Which ARM Cortex-M CMSIS function initiates a software-commanded system reset?
A NVIC_SystemReset()
B CPU_Halt()
C WDT_Clear()
D OS_Exit()
Detailed Explanation: NVIC_SystemReset() sets the SYSRESETREQ bit in the Application Interrupt and Reset Control Register (AIRCR), triggering an immediate hardware reset.