| 112 | } |
| 113 | |
| 114 | inline void setup(double timeout_seconds = 20.0) { |
| 115 | // Check if watchdog should be disabled |
| 116 | const char* disable_watchdog = getenv("FASTLED_DISABLE_TIMEOUT_WATCHDOG"); |
| 117 | if (disable_watchdog && (strcmp(disable_watchdog, "1") == 0 || strcmp(disable_watchdog, "true") == 0)) { // ok ctype |
| 118 | printf("Timeout watchdog disabled (FASTLED_DISABLE_TIMEOUT_WATCHDOG set)\n"); |
| 119 | return; |
| 120 | } |
| 121 | |
| 122 | // Check for timeout override from environment |
| 123 | const char* timeout_env = getenv("FASTLED_TEST_TIMEOUT"); |
| 124 | if (timeout_env) { |
| 125 | double parsed_timeout = atof(timeout_env); |
| 126 | if (parsed_timeout > 0.0) { |
| 127 | timeout_seconds = parsed_timeout; |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | g_timeout_seconds = timeout_seconds; |
| 132 | g_watchdog_active.store(true); |
| 133 | g_should_exit.store(false); |
| 134 | g_watchdog_triggered.store(false); |
| 135 | |
| 136 | // Duplicate handle to main thread for stack walking |
| 137 | DuplicateHandle( |
| 138 | GetCurrentProcess(), |
| 139 | GetCurrentThread(), |
| 140 | GetCurrentProcess(), |
| 141 | &g_main_thread, |
| 142 | 0, |
| 143 | FALSE, |
| 144 | DUPLICATE_SAME_ACCESS |
| 145 | ); |
| 146 | |
| 147 | // Start watchdog thread |
| 148 | g_timer_thread = CreateThread( |
| 149 | nullptr, |
| 150 | 0, |
| 151 | watchdog_timer_thread, |
| 152 | &g_timeout_seconds, |
| 153 | 0, |
| 154 | nullptr |
| 155 | ); |
| 156 | |
| 157 | if (g_timer_thread != nullptr) { |
| 158 | printf("⏱️ Internal timeout watchdog enabled (%.1f seconds)\n", timeout_seconds); |
| 159 | } else { |
| 160 | fprintf(stderr, "Warning: Failed to create watchdog thread\n"); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | inline void cancel() { |
| 165 | if (!g_watchdog_active.load()) { |