From 19f219f731f29503c8e4d432935d3ea558cc1659 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Fri, 13 Mar 2015 16:32:53 +0300 Subject: [PATCH] Tcl exception codes cleanup, shutdown command amendments This patch might influence openocd Tcl commands behaviour in subtle ways, please give it a nice testing. The idea is that if an OpenOCD Tcl command returns an error, an exception is raised, and then the return code is propogated all the way up (or to the "catch" if present). This allows to detect "shutdown" which is not actually an error but has to raise an exception to stop execution of the commands that follow it in the script. openocd_thread special-cases shutdown because it should then terminate OpenOCD with a success error code, unless shutdown was called with an optional "error" argument which means terminate with a non-zero exit code. Change-Id: I7b6fa8a2e24c947dc45d8def0008b4b007c478b3 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/2600 Tested-by: jenkins Reviewed-by: Juha Niskanen Reviewed-by: Jens Bauer Reviewed-by: Oleksij Rempel --- doc/openocd.texi | 6 ++++-- src/flash/startup.tcl | 4 ++-- src/helper/command.c | 36 +++++++++++++++++------------------- src/helper/startup.tcl | 6 ++++-- src/openocd.c | 14 +++++++++++--- src/server/server.c | 12 ++++++++++-- 6 files changed, 48 insertions(+), 30 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 4bec637f3..e418e0500 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6486,8 +6486,10 @@ Useful in connection with script files (@command{script} command and @command{target_name} configuration). @end deffn -@deffn Command shutdown -Close the OpenOCD daemon, disconnecting all clients (GDB, telnet, other). +@deffn Command shutdown [@option{error}] +Close the OpenOCD daemon, disconnecting all clients (GDB, telnet, +other). If option @option{error} is used, OpenOCD will return a +non-zero exit code to the parent process. @end deffn @anchor{debuglevel} diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index 7a96a3e3b..fbb8d8ee4 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -8,8 +8,8 @@ proc program_error {description exit} { if {$exit == 1} { - echo $description - shutdown + echo $description + shutdown error } error $description diff --git a/src/helper/command.c b/src/helper/command.c index 9d19cff4f..a0aa9e857 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -121,7 +121,7 @@ static int command_retval_set(Jim_Interp *interp, int retval) if (return_retval != NULL) *return_retval = retval; - return (retval == ERROR_OK) ? JIM_OK : JIM_ERR; + return (retval == ERROR_OK) ? JIM_OK : retval; } extern struct command_context *global_cmd_ctx; @@ -659,24 +659,7 @@ int command_run_line(struct command_context *context, char *line) } Jim_DeleteAssocData(interp, "context"); } - if (retcode == JIM_ERR) { - if (retval == ERROR_COMMAND_CLOSE_CONNECTION) { - /* Shutdown request is not an error */ - return ERROR_OK; - } else { - /* We do not print the connection closed error message */ - Jim_MakeErrorMessage(interp); - LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); - } - if (retval == ERROR_OK) { - /* It wasn't a low level OpenOCD command that failed */ - return ERROR_FAIL; - } - return retval; - } else if (retcode == JIM_EXIT) { - /* ignore. - * exit(Jim_GetExitCode(interp)); */ - } else { + if (retcode == JIM_OK) { const char *result; int reslen; @@ -696,7 +679,22 @@ int command_run_line(struct command_context *context, char *line) LOG_USER_N("\n"); } retval = ERROR_OK; + } else if (retcode == JIM_EXIT) { + /* ignore. + * exit(Jim_GetExitCode(interp)); */ + } else if (retcode == ERROR_COMMAND_CLOSE_CONNECTION) { + return retcode; + } else { + Jim_MakeErrorMessage(interp); + LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); + + if (retval == ERROR_OK) { + /* It wasn't a low level OpenOCD command that failed */ + return ERROR_FAIL; + } + return retval; } + return retval; } diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl index 926d26b63..4ca2cabc2 100644 --- a/src/helper/startup.tcl +++ b/src/helper/startup.tcl @@ -16,10 +16,12 @@ proc exit {} { proc ocd_bouncer {name args} { set cmd [format "ocd_%s" $name] set type [eval ocd_command type $cmd $args] + set errcode error if {$type == "native"} { return [eval $cmd $args] } else {if {$type == "simple"} { - if {[catch {eval $cmd $args}] == 0} { + set errcode [catch {eval $cmd $args}] + if {$errcode == 0} { return "" } else { # 'classic' commands output error message as part of progress output @@ -32,7 +34,7 @@ proc ocd_bouncer {name args} { } else { set errmsg [format "invalid subcommand \"%s\"" $args] }}} - return -code error $errmsg + return -code $errcode $errmsg } # Try flipping / and \ to find file if the filename does not diff --git a/src/openocd.c b/src/openocd.c index b0dd21ab2..4d4dc2c83 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -283,7 +283,9 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct return ERROR_FAIL; ret = parse_config_file(cmd_ctx); - if (ret != ERROR_OK) + if (ret == ERROR_COMMAND_CLOSE_CONNECTION) + return ERROR_OK; + else if (ret != ERROR_OK) return ERROR_FAIL; ret = server_init(cmd_ctx); @@ -296,9 +298,15 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct return ERROR_FAIL; } - server_loop(cmd_ctx); + ret = server_loop(cmd_ctx); - return server_quit(); + int last_signal = server_quit(); + if (last_signal != ERROR_OK) + return last_signal; + + if (ret != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; } /* normally this is the main() function entry, but if OpenOCD is linked diff --git a/src/server/server.c b/src/server/server.c index 73d8b5b65..7e90d89fd 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -44,7 +44,8 @@ static struct service *services; -/* shutdown_openocd == 1: exit the main event loop, and quit the debugger */ +/* shutdown_openocd == 1: exit the main event loop, and quit the + * debugger; 2: quit with non-zero return code */ static int shutdown_openocd; /* store received signal to exit application by killing ourselves */ @@ -499,7 +500,7 @@ int server_loop(struct command_context *command_context) #endif } - return ERROR_OK; + return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL; } #ifdef _WIN32 @@ -608,6 +609,13 @@ COMMAND_HANDLER(handle_shutdown_command) shutdown_openocd = 1; + if (CMD_ARGC == 1) { + if (!strcmp(CMD_ARGV[0], "error")) { + shutdown_openocd = 2; + return ERROR_FAIL; + } + } + return ERROR_COMMAND_CLOSE_CONNECTION; }