diff --git a/src/target/target.c b/src/target/target.c index 7d3861ab5..3a5651309 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3046,44 +3046,41 @@ static int handle_target(void *priv) is_jtag_poll_safe() && target; target = target->next) { - if (!target->tap->enabled) + /* This function only gets called every polling_interval, so + * allow some slack in the time comparison. Otherwise, if we + * schedule for now+polling_interval, the next poll won't + * actually happen until a polling_interval later. */ + if (!target->tap->enabled || + power_dropout || + srst_asserted || + timeval_ms() + polling_interval / 2 < target->backoff.next_attempt) continue; - if (target->backoff.times > target->backoff.count) { - /* do not poll this time as we failed previously */ - target->backoff.count++; - continue; + /* polling may fail silently until the target has been examined */ + retval = target_poll(target); + if (retval == ERROR_OK) { + target->backoff.interval = polling_interval; + } else { + /* Increase interval between polling up to 5000ms */ + target->backoff.interval = MAX(polling_interval, + MIN(target->backoff.interval * 2 + 1, 5000)); + /* Tell GDB to halt the debugger. This allows the user to run + * monitor commands to handle the situation. */ + target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } - target->backoff.count = 0; + target->backoff.next_attempt = timeval_ms() + target->backoff.interval; + LOG_TARGET_DEBUG(target, "target_poll() -> %d, next attempt in %dms", + retval, target->backoff.interval); - /* only poll target if we've got power and srst isn't asserted */ - if (!power_dropout && !srst_asserted) { - /* polling may fail silently until the target has been examined */ - retval = target_poll(target); + if (retval != ERROR_OK && examine_attempted) { + target_reset_examined(target); + retval = target_examine_one(target); if (retval != ERROR_OK) { - /* 100ms polling interval. Increase interval between polling up to 5000ms */ - if (target->backoff.times * polling_interval < 5000) - target->backoff.times = MIN(target->backoff.times * 2 + 1, - 5000 / polling_interval); - - /* Tell GDB to halt the debugger. This allows the user to - * run monitor commands to handle the situation. - */ - target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); + LOG_TARGET_DEBUG(target, "Examination failed, GDB will be halted. " + "Polling again in %dms", + target->backoff.interval); + return retval; } - if (target->backoff.times > 0 && examine_attempted) { - LOG_DEBUG("[%s] Polling failed, trying to reexamine", target_name(target)); - target_reset_examined(target); - retval = target_examine_one(target); - if (retval != ERROR_OK) { - LOG_DEBUG("[%s] Examination failed, GDB will be halted. Polling again in %dms", - target_name(target), target->backoff.times * polling_interval); - return retval; - } - } - - /* Since we succeeded, we reset backoff count */ - target->backoff.times = 0; } } diff --git a/src/target/target.h b/src/target/target.h index 4b494d8d5..726a14d3f 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -117,8 +117,8 @@ struct gdb_service { /* target back off timer */ struct backoff_timer { - int times; - int count; + int64_t next_attempt; + unsigned int interval; }; /* split target registers into multiple class */ @@ -199,6 +199,9 @@ struct target { struct rtos *rtos; /* Instance of Real Time Operating System support */ bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto" * and must be detected when symbols are offered */ + /* Track when next to poll(). If polling is failing, we don't want to + * poll too quickly because we'll just overwhelm the user with error + * messages. */ struct backoff_timer backoff; int smp; /* add some target attributes for smp support */ struct list_head *smp_targets; /* list all targets in this smp group/cluster