From: Antonio Borneo Date: Fri, 1 Jun 2018 16:31:49 +0000 (+0200) Subject: server: explicitly call "shutdown" when catch CTRL-C or a signal X-Git-Tag: v0.11.0-rc1~1030 X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=5e13e0114105c51a8afa6ac2cb40523ac269ad78 server: explicitly call "shutdown" when catch CTRL-C or a signal Every TCL command can be renamed (or deleted) and then replaced by a TCL proc that has the same name of the original TCL command. This can be used either to completely replace an existing command or to wrap the original command to extend its functionality. This applies also to the OpenOCD command "shutdown" and can be useful, for example, to set back some default value to the target before quitting OpenOCD. E.g. (TCL code): rename shutdown original_shutdown proc shutdown {} { puts "This is my implementation of shutdown" # my own stuff before exit OpenOCD original_shutdown } Unfortunately, sending a signal (or pressing CTRL-C) to terminate OpenOCD doesn't trigger calling the original "shutdown" command nor its (eventual) replacement. Detect if the main loop is terminated by an external signal and in such case execute explicitly the command "shutdown". Replace with enum the magic numbers assumed by "shutdown_openocd". Please notice that it's possible to write a custom "shutdown" TCL proc that does not call the original "shutdown" command. This is useful, for example, to prevent the user to quit OpenOCD by typing "shutdown" in the telnet session. Such case will not prevent OpenOCD to terminate when receiving a signal; OpenOCD will quit after executing the custom "shutdown" command. Change-Id: I86b8f9eab8dbd7a28dad58b8cafd97caa7a82f43 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4551 Tested-by: jenkins Reviewed-by: Tomas Vanek --- diff --git a/doc/openocd.texi b/doc/openocd.texi index 43ebf8cb28..16aa26bf54 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7390,6 +7390,19 @@ Useful in connection with script files 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. + +Like any TCL commands, also @command{shutdown} can be redefined, e.g.: +@example +# redefine shutdown +rename shutdown original_shutdown +proc shutdown @{@} @{ + puts "This is my implementation of shutdown" + # my own stuff before exit OpenOCD + original_shutdown +@} +@end example +If user types CTRL-C or kills OpenOCD, either the command @command{shutdown} +or its replacement will be automatically executed before OpenOCD exits. @end deffn @anchor{debuglevel} diff --git a/src/server/server.c b/src/server/server.c index 06a2f39de8..bc5856cccb 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -46,9 +46,13 @@ static struct service *services; -/* shutdown_openocd == 1: exit the main event loop, and quit the - * debugger; 2: quit with non-zero return code */ -static int shutdown_openocd; +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 */ + SHUTDOWN_WITH_ERROR_CODE, /* set by shutdown command; quit with non-zero return code */ + SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */ +}; +static enum shutdown_reason shutdown_openocd = CONTINUE_MAIN_LOOP; /* store received signal to exit application by killing ourselves */ static int last_signal; @@ -413,7 +417,7 @@ int server_loop(struct command_context *command_context) LOG_ERROR("couldn't set SIGPIPE to SIG_IGN"); #endif - while (!shutdown_openocd) { + while (shutdown_openocd == CONTINUE_MAIN_LOOP) { /* monitor sockets for activity */ fd_max = 0; FD_ZERO(&read_fds); @@ -537,7 +541,7 @@ int server_loop(struct command_context *command_context) service->type == CONNECTION_STDINOUT) { /* if connection uses a pipe then * shutdown openocd on error */ - shutdown_openocd = 1; + shutdown_openocd = SHUTDOWN_REQUESTED; } remove_connection(service, c); LOG_INFO("dropped '%s' connection", @@ -555,20 +559,24 @@ int server_loop(struct command_context *command_context) MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) - shutdown_openocd = 1; + shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; } #endif } - return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL; + /* 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"); + + return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK; } void sig_handler(int sig) { /* store only first signal that hits us */ - if (!shutdown_openocd) { + if (shutdown_openocd == CONTINUE_MAIN_LOOP) { + shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; last_signal = sig; - shutdown_openocd = 1; LOG_DEBUG("Terminating on Signal %d", sig); } else LOG_DEBUG("Ignored extra Signal %d", sig); @@ -578,7 +586,7 @@ void sig_handler(int sig) #ifdef _WIN32 BOOL WINAPI ControlHandler(DWORD dwCtrlType) { - shutdown_openocd = 1; + shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; return TRUE; } #else @@ -702,11 +710,11 @@ COMMAND_HANDLER(handle_shutdown_command) { LOG_USER("shutdown command invoked"); - shutdown_openocd = 1; + shutdown_openocd = SHUTDOWN_REQUESTED; if (CMD_ARGC == 1) { if (!strcmp(CMD_ARGV[0], "error")) { - shutdown_openocd = 2; + shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE; return ERROR_FAIL; } }