What is the Watchdog?
The Watchdog module detects when a system or task has stopped responding. You create a watchdog with a timeout period, then periodically "kick" it. If the watchdog times out without a kick, it triggers a recovery action (log event, enter safe-state, reboot, custom callback, or failover).
Key principle: If you can't prove the system is alive, assume it's dead.
Watchdog Types
Four types for different monitoring scenarios:
RTE_WATCHDOG_SYSTEM - Entire system liveness (main loop heartbeat)
RTE_WATCHDOG_TASK - Specific task/thread heartbeat
RTE_WATCHDOG_CHANNEL - IPC/redundancy channel health
RTE_WATCHDOG_CHECKPOINT - Execution checkpoint barrier
Recovery Actions
When watchdog times out, it can trigger different actions:
LOG - Log the event only
SAFESTATE - Enter SAFE state via RTE_SAFESTATE()
REBOOT - Trigger system reboot via RTE_REBOOT()
FAILOVER - Failover to backup (distributed systems)
CUSTOM - Custom callback provided by application
Quick Start
1. Include Header
#include "rte/watchdog/rte_watchdog.h"
2. Create Watchdog
rte_watchdog_storage_t wd_storage;
.name = "main_watchdog",
.timeout_ms = 100,
.custom_action = NULL,
.context = NULL
};
rte_watchdog_t wd;
rte_status_t rte_watchdog_create(rte_watchdog_t *handle_out, const rte_watchdog_config_t *config)
Create a watchdog.
@ RTE_WATCHDOG_ACTION_SAFESTATE
3. Start Watchdog
rte_status_t rte_watchdog_start(rte_watchdog_t watchdog)
Start watchdog timer.
4. Kick Watchdog Regularly
while (running) {
process_messages();
handle_timers();
compute_output();
break;
}
sleep_ms(50);
}
rte_status_t
Common result/status codes.
rte_status_t rte_watchdog_kick(rte_watchdog_t watchdog)
Kick (pet) watchdog - prove liveness.
Practical Examples
Example 1: System Watchdog (Main Loop Heartbeat)
typedef struct {
rte_watchdog_t system_wd;
uint32_t cycle_count;
uint32_t errors;
} app_t;
void app_init(app_t *app) {
rte_watchdog_storage_t *storage = malloc(sizeof(*storage));
.name = "app_main_loop",
.timeout_ms = 100,
.context = app
};
}
void app_main_loop(app_t *app) {
while (running) {
uint64_t cycle_start = get_time_ms();
process_inputs();
compute_logic();
send_outputs();
app->cycle_count++;
log_error("Watchdog fired, terminating");
break;
}
uint64_t elapsed = get_time_ms() - cycle_start;
if (elapsed < 50) {
sleep_ms(50 - elapsed);
} else {
log_warning("Cycle overrun: %llu ms", elapsed);
}
}
}
Example 2: Custom Callback on Timeout
void my_watchdog_handler(void *context) {
app_t *app = (app_t *)context;
log_critical("Watchdog timeout detected");
log_critical(" Cycles executed: %u", app->cycle_count);
log_critical(" Errors so far: %u", app->errors);
}
void app_with_custom_handler(app_t *app) {
.name = "app_custom_wd",
.timeout_ms = 200,
.custom_action = my_watchdog_handler,
.context = app
};
rte_watchdog_t wd;
}
@ RTE_WATCHDOG_ACTION_CUSTOM
Timeout Selection
Choose timeout based on your main loop cycle time with safety margin:
Cycle Time Recommended Timeout Reasoning
──────────────────────────────────────────────────────────
10 ms 30-50 ms Allow 3-5× margin
50 ms 150-250 ms Allow 3-5× margin
100 ms 300-500 ms Allow 3-5× margin
1 second 3-5 seconds Allow 3-5× margin
Safety margin accounts for:
- Jitter in cycle timing
- Occasional heavy workloads
- System clock drift
Too tight (1-2×): False positives on normal variation Too loose (10×+): Late detection of actual hangs
Common Patterns
Pattern 1: Conditional Kick (Fail-Safe Default)
Only kick if operation succeeds:
return rc;
}
const char * rte_status_to_string(rte_status_t status)
Returns a short, static, human-readable string for a status code. Intended for diagnostics/logging on...
This pattern makes watchdog a health indicator: if operation fails repeatedly, watchdog will eventually timeout and trigger recovery.
Pattern 2: Check Watchdog Status
Monitor watchdog health:
printf("Watchdog: kicks=%u fires=%u time_until=%u ms\n",
log_warning(
"Watchdog has fired %u times", status.
fires);
}
rte_status_t rte_watchdog_get_status(rte_watchdog_t watchdog, rte_watchdog_status_t *status_out)
Get watchdog status.
Watchdog health/status information.
rte_duration_ms_t time_until_fire
Best Practices
- Set timeout to 2-5× your cycle time
- Measured, not guessed
- Account for worst-case jitter
- Kick watchdog near end of loop
- After all critical work done
- Before sleep (ensures all work completed)
- Use conditional kick pattern
- Only kick on success
- Watchdog becomes health indicator
- Automatic recovery on transient failures
- Stop watchdog on intentional shutdown
rte_status_t rte_watchdog_stop(rte_watchdog_t watchdog)
Stop watchdog timer.
- Prevents false timeouts during graceful shutdown
- Test watchdog behavior
- Intentionally omit kicks
- Verify timeout and recovery action work
- Part of safety verification
See Also