From: Antonio Borneo Date: Fri, 26 Feb 2021 21:35:39 +0000 (+0100) Subject: target: avoid polling during 'resumed' event handler X-Git-Tag: v0.11.0~2 X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=23d8831391bbd167e0061388c87e7ecf7b9891a7 target: avoid polling during 'resumed' event handler OpenOCD is based on a single main loop that schedules all the activities. At the execution of a TCL command, the timestamp is checked to eventually trigger the polling of the targets. This means that by executing a TCL command the polling can be triggered and detect a change of target's state. When openocd 'resumes' a target, the target can halt again by hitting a breakpoint. The 'resumed' event handler is started just after the target has been resumed, but it triggers a polling before the execution of its very first instruction. If the polling finds the target halted, it will run the 'halted' event handler, that will then be executed 'before' the pending 'resumed' handler. In case of gdb, a 'continue' command will restart the target but, polling (and halt detection) executed before the end of the resume process will hide the halt. As a consequence, the gdb will not be informed of the halt and will remains waiting as if the target is still running without showing the prompt. This can be verified by running on the target a firmware with a loop, run openocd with a dummy 'resumed' event, and let gdb to set a breakpoint in the loop. A 'continue' command will cause the target to halt again by hitting the breakpoint at the next loop iteration, but gdb will loose it and will not return the prompt. openocd -f board/st_nucleo_f4.cfg -c \ 'stm32f4x.cpu configure -event resumed {echo hello}' arm-none-eabi-gdb -ex 'target remote :3333' -ex 'b *$pc' -ex c Disable the polling while executing target's resume(). Document it and provide hints to developers to cope with future implementation. Change-Id: I3be830a8e7c2ef6278617cb4547a4d676b0ddeb5 Signed-off-by: Antonio Borneo Reported-by: Габитов Александр Фаритович Reviewed-on: http://openocd.zylin.com/6074 Reviewed-by: Tomas Vanek Tested-by: jenkins --- diff --git a/doc/openocd.texi b/doc/openocd.texi index 4b31cbd0f1..a5b94362f5 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5035,6 +5035,19 @@ when reset disables PLLs needed to use a fast clock. @* After target hardware trace configuration was changed @end itemize +@quotation Note +OpenOCD events are not supposed to be preempt by another event, but this +is not enforced in current code. Only the target event @b{resumed} is +executed with polling disabled; this avoids polling to trigger the event +@b{halted}, reversing the logical order of execution of their handlers. +Future versions of OpenOCD will prevent the event preemption and will +disable the schedule of polling during the event execution. Do not rely +on polling in any event handler; this means, don't expect the status of +a core to change during the execution of the handler. The event handler +will have to enable polling or use @command{$target_name arp_poll} to +check if the core has changed status. +@end quotation + @node Flash Commands @chapter Flash Commands diff --git a/src/target/target.c b/src/target/target.c index 033fc07142..cab84b06be 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -637,7 +637,18 @@ int target_resume(struct target *target, int current, target_addr_t address, * we poll. The CPU can even halt at the current PC as a result of * a software breakpoint being inserted by (a bug?) the application. */ + /* + * resume() triggers the event 'resumed'. The execution of TCL commands + * in the event handler causes the polling of targets. If the target has + * already halted for a breakpoint, polling will run the 'halted' event + * handler before the pending 'resumed' handler. + * Disable polling during resume() to guarantee the execution of handlers + * in the correct order. + */ + bool save_poll = jtag_poll_get_enabled(); + jtag_poll_set_enabled(false); retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution); + jtag_poll_set_enabled(save_poll); if (retval != ERROR_OK) return retval;