|
From: openocd-gerrit <ope...@us...> - 2026-07-25 10:40:02
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via ca1a5e98f00573956a584c7315d2f67e4c38d227 (commit)
from 51eade7c4abc00a48688a153ea36016c6bfb9356 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit ca1a5e98f00573956a584c7315d2f67e4c38d227
Author: Jan Matyas <jan...@co...>
Date: Mon Jan 5 07:27:20 2026 +0100
server: Allow OpenOCD to shut down with user-specified code
Improve the "shutdown" command so that the user can optionally
specify a concrete exit code for OpenOCD.
The change is backward-compatible:
shutdown ;# same as: shutdown 0
shutdown error ;# same as: shutdown 1
shutdown 5 ;# new capability: concrete exit code
This feature is useful when different errors can occur in a given Tcl
script, and the parent process (that launched OpenOCD) needs to
distinguish between these errors.
Concrete use case (example): When testing OpenOCD in an automated
way, some tests may need to be skipped because they are not applicable
for the given situation (e.g. for the target under test). In that case,
the Tcl script can now exit with a specific code, which the parent
process will then interpret as a skipped test, not as a test failure.
While making the change, the code related to the shutdown reason
was cleaned up.
Documentation was updated accordingly.
Change-Id: I4279b80853db55b1f0c7f930883fcd7f16cae00c
Signed-off-by: Jan Matyas <jan...@co...>
Reviewed-on: https://review.openocd.org/c/openocd/+/9381
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 89900b06a..df0e18d78 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -9585,16 +9585,28 @@ Useful in connection with script files
(@command{script} command and @command{target_name} configuration).
@end deffn
-@deffn {Command} {shutdown} [@option{error}]
-Close the OpenOCD server, disconnecting all clients (GDB, telnet,
-other). If option @option{error} is used, OpenOCD will return a
-non-zero exit code to the parent process.
+@deffn {Command} {shutdown} [@option{error} | exit_status_code]
+Close the OpenOCD server, disconnecting all clients (GDB, telnet and
+others). Then the OpenOCD process quits.
+
+The optional argument to @command{shutdown} allows to specify a concrete
+exit status for the OpenOCD process. If omitted, exit status zero
+will be used (denoting successful execution).
+
+Command @command{shutdown error} is a synonym for @command{shutdown 1}
+for backward compatibility with older OpenOCD versions.
+
+"Exit status" (also referred to as "exit code" or "exit value") is an integer
+number in the range 0 - 255 which denotes whether a process exited successfully
+or whether an error occurred. Zero exit status means success whereas non-zero
+value denotes an error. The exit status can be obtained and inspected by
+the parent process (for instance via @command{$?} in a shell command line).
If user types CTRL-C or kills OpenOCD, the command @command{shutdown}
-will be automatically executed to cause OpenOCD to exit.
+will also be automatically executed to cause OpenOCD to exit.
-It is possible to specify, in the Tcl list @var{pre_shutdown_commands} , a
-set of commands to be automatically executed before @command{shutdown} , e.g.:
+It is possible to specify, in the Tcl list @var{pre_shutdown_commands}, a
+set of commands to be automatically executed before @command{shutdown}, e.g.:
@example
lappend pre_shutdown_commands @{echo "Goodbye, my friend ..."@}
lappend pre_shutdown_commands @{echo "see you soon !"@}
diff --git a/src/openocd.c b/src/openocd.c
index f3e1bee48..efbbf006b 100644
--- a/src/openocd.c
+++ b/src/openocd.c
@@ -275,7 +275,8 @@ static struct command_context *setup_command_handler(Jim_Interp *interp)
return cmd_ctx;
}
-/** OpenOCD runtime meat that can become single-thread in future. It parse
+/**
+ * OpenOCD runtime meat that can become single-thread in future. It parses
* commandline, reads configuration, sets up the target and starts server loop.
* Commandline arguments are passed into this function from openocd_main().
*/
@@ -291,6 +292,8 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct
ret = parse_config_file(cmd_ctx);
if (ret == ERROR_COMMAND_CLOSE_CONNECTION) {
+ /* Shutdown command encountered while processing the initial
+ * commands/scripts. */
server_quit(); /* gdb server may be initialized by -c init */
return ERROR_OK;
} else if (ret != ERROR_OK) {
@@ -310,14 +313,10 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct
}
}
- ret = server_loop(cmd_ctx);
+ server_loop(cmd_ctx);
- int last_signal = server_quit();
- if (last_signal != ERROR_OK)
- return last_signal;
+ server_quit();
- if (ret != ERROR_OK)
- return ERROR_FAIL;
return ERROR_OK;
}
@@ -326,8 +325,6 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct
* application will have it's own implementation of main(). */
int openocd_main(int argc, char *argv[])
{
- int ret;
-
/* initialize commandline interface */
struct command_context *cmd_ctx;
@@ -349,7 +346,7 @@ int openocd_main(int argc, char *argv[])
server_host_os_entry();
/* Start the executable meat that can evolve into thread in future. */
- ret = openocd_thread(argc, argv, cmd_ctx);
+ int ret = openocd_thread(argc, argv, cmd_ctx);
flash_free_all_banks();
gdb_service_free();
@@ -382,10 +379,17 @@ int openocd_main(int argc, char *argv[])
__gcov_dump();
#endif
- if (ret == ERROR_FAIL)
+ if (ret != ERROR_OK) {
+ /* An error occurred before the server could be fully started.
+ * For example during the processing of initial commands/scripts. */
return EXIT_FAILURE;
- else if (ret != ERROR_OK)
- exit_on_signal(ret);
+ }
+
+ // Otherwise check the shutdown reason of the server
+ if (server_terminated_by_signal())
+ // Server terminated by a signal.
+ return exit_on_signal(server_get_last_signal_number());
- return ret;
+ // Server terminated by shutdown command.
+ return server_get_exit_status_code();
}
diff --git a/src/server/server.c b/src/server/server.c
index 9e40d4d00..dce626201 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -35,8 +35,6 @@
#include <netinet/tcp.h>
#endif
-static struct service *services;
-
enum shutdown_reason {
CONTINUE_MAIN_LOOP, /* stay in main event loop */
SHUTDOWN_REQUESTED, /* set by shutdown command; exit the event loop and quit the debugger */
@@ -44,9 +42,15 @@ enum shutdown_reason {
SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */
};
+static struct service *services;
+
static volatile sig_atomic_t shutdown_openocd = CONTINUE_MAIN_LOOP;
-/* store received signal to exit application by killing ourselves */
+/* Received signal number, later used to kill ourselves.
+ * Only relevant for SHUTDOWN_WITH_SIGNAL_CODE. */
static volatile sig_atomic_t last_signal;
+/* Exit status to use. Only relevant for SHUTDOWN_REQUESTED
+ * or SHUTDOWN_WITH_ERROR_CODE. */
+static uint8_t openocd_exit_status_code;
/* set the polling period to 100ms */
static int polling_period = 100;
@@ -428,7 +432,7 @@ void server_keep_clients_alive(void)
s->keep_client_alive(c);
}
-int server_loop(struct command_context *command_context)
+void server_loop(struct command_context *command_context)
{
struct service *service;
@@ -503,7 +507,9 @@ int server_loop(struct command_context *command_context)
FD_ZERO(&read_fds);
else {
LOG_ERROR("error during select: %s", strerror(errno));
- return ERROR_FAIL;
+ shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE;
+ openocd_exit_status_code = EXIT_FAILURE;
+ return;
}
#else
@@ -511,7 +517,9 @@ int server_loop(struct command_context *command_context)
FD_ZERO(&read_fds);
else {
LOG_ERROR("error during select: %s", strerror(errno));
- return ERROR_FAIL;
+ shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE;
+ openocd_exit_status_code = EXIT_FAILURE;
+ return;
}
#endif
}
@@ -601,11 +609,33 @@ int server_loop(struct command_context *command_context)
#endif
}
+ assert(shutdown_openocd == SHUTDOWN_REQUESTED ||
+ shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ||
+ shutdown_openocd == SHUTDOWN_WITH_SIGNAL_CODE);
+
/* when quit for signal or CTRL-C, run (eventually user implemented) "shutdown" */
if (shutdown_openocd == SHUTDOWN_WITH_SIGNAL_CODE)
command_run_line(command_context, "shutdown");
+}
+
+bool server_terminated_by_signal(void)
+{
+ return shutdown_openocd == SHUTDOWN_WITH_SIGNAL_CODE;
+}
+
+int server_get_last_signal_number(void)
+{
+ /* This value is only meaningful if the shutdown reason is signal.
+ * The caller should check the shutdown reason first. */
+ assert(server_terminated_by_signal());
+
+ return last_signal;
+}
- return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK;
+uint8_t server_get_exit_status_code(void)
+{
+ assert(!server_terminated_by_signal());
+ return openocd_exit_status_code;
}
static void sig_handler(int sig)
@@ -704,19 +734,14 @@ int server_init(struct command_context *cmd_ctx)
return ERROR_OK;
}
-int server_quit(void)
+void server_quit(void)
{
remove_services();
target_quit();
#ifdef _WIN32
SetConsoleCtrlHandler(control_handler, FALSE);
-
- return ERROR_OK;
#endif
-
- /* return signal number so we can kill ourselves */
- return last_signal;
}
void server_free(void)
@@ -729,12 +754,16 @@ void server_free(void)
free(bindto_name);
}
-void exit_on_signal(int sig)
+int exit_on_signal(int sig)
{
#ifndef _WIN32
- /* bring back default system handler and kill yourself */
+ // *nix: Bring back the default system handler and kill self
signal(sig, SIG_DFL);
- kill(getpid(), sig);
+ kill(getpid(), sig); /* does not return */
+ __builtin_unreachable();
+#else
+ // On Windows, simply use the signal number as the exit code
+ return sig;
#endif
}
@@ -766,19 +795,36 @@ bool openocd_is_shutdown_pending(void)
/* tell the server we want to shut down */
COMMAND_HANDLER(handle_shutdown_command)
{
- LOG_USER("shutdown command invoked");
-
- shutdown_openocd = SHUTDOWN_REQUESTED;
+ if (CMD_ARGC > 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
- command_run_line(CMD_CTX, "_run_pre_shutdown_commands");
+ LOG_USER("shutdown command invoked");
- if (CMD_ARGC == 1) {
- if (!strcmp(CMD_ARGV[0], "error")) {
- shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE;
- return ERROR_FAIL;
+ if (CMD_ARGC == 0) {
+ /* When "shutdown" (without parameters) is auto-executed
+ * as a result of a signal, keep the alredy-set shutdown reason
+ * unchanged. */
+ if (shutdown_openocd != SHUTDOWN_WITH_SIGNAL_CODE) {
+ // Default exit code is zero (success)
+ shutdown_openocd = SHUTDOWN_REQUESTED;
+ openocd_exit_status_code = 0;
+ }
+ } else {
+ uint8_t code;
+ if (strcmp(CMD_ARGV[0], "error") == 0) {
+ /* "shutdown error" is a synonym of "shutdown 1"
+ * for backward compatibility. */
+ code = 1;
+ } else {
+ COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], code);
}
+
+ shutdown_openocd = (code == 0) ? SHUTDOWN_REQUESTED : SHUTDOWN_WITH_ERROR_CODE;
+ openocd_exit_status_code = code;
}
+ command_run_line(CMD_CTX, "_run_pre_shutdown_commands");
+
return ERROR_COMMAND_CLOSE_CONNECTION;
}
@@ -832,8 +878,8 @@ static const struct command_registration server_command_handlers[] = {
.name = "shutdown",
.handler = &handle_shutdown_command,
.mode = COMMAND_ANY,
- .usage = "",
- .help = "shut the server down",
+ .usage = "['error'|exit_code]",
+ .help = "shut down OpenOCD process",
},
{
.name = "exit",
diff --git a/src/server/server.h b/src/server/server.h
index 393dba769..bf3758274 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -93,13 +93,16 @@ int server_host_os_close(void);
int server_preinit(void);
int server_init(struct command_context *cmd_ctx);
-int server_quit(void);
+void server_quit(void);
void server_free(void);
-void exit_on_signal(int sig);
+int exit_on_signal(int sig);
void server_keep_clients_alive(void);
-int server_loop(struct command_context *command_context);
+void server_loop(struct command_context *command_context);
+bool server_terminated_by_signal(void);
+int server_get_last_signal_number(void);
+uint8_t server_get_exit_status_code(void);
int server_register_commands(struct command_context *context);
-----------------------------------------------------------------------
Summary of changes:
doc/openocd.texi | 26 ++++++++++----
src/openocd.c | 32 +++++++++--------
src/server/server.c | 98 +++++++++++++++++++++++++++++++++++++++--------------
src/server/server.h | 9 +++--
4 files changed, 115 insertions(+), 50 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|