Here is a v2 that handles the Windows case that I seemingly missed in my first readthrough of this code.
-- Tristan Partin Neon (https://neon.tech)
From 3cff6aec8f154eb8a47524efc15f16a6b7e95f37 Mon Sep 17 00:00:00 2001 From: Tristan Partin <tris...@neon.tech> Date: Mon, 22 May 2023 08:07:37 -0500 Subject: [PATCH postgres v2 1/2] Move exit code definitions to fe_utils This makes sharing exit code definitions much simpler. --- src/bin/psql/common.c | 3 ++- src/bin/psql/mainloop.c | 1 + src/bin/psql/settings.h | 13 ------------- src/bin/psql/startup.c | 1 + src/include/fe_utils/exit_codes.h | 24 ++++++++++++++++++++++++ 5 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 src/include/fe_utils/exit_codes.h diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index c0e6e8e6ed..a36e188944 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -25,6 +25,7 @@ #include "copy.h" #include "crosstabview.h" #include "fe_utils/cancel.h" +#include "fe_utils/exit_codes.h" #include "fe_utils/mbprint.h" #include "fe_utils/string_utils.h" #include "portability/instr_time.h" @@ -273,7 +274,7 @@ psql_cancel_callback(void) void psql_setup_cancel_handler(void) { - setup_cancel_handler(psql_cancel_callback); + setup_cancel_handler(psql_cancel_callback, NULL); } diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c index 692c6db34c..98df0e0a97 100644 --- a/src/bin/psql/mainloop.c +++ b/src/bin/psql/mainloop.c @@ -10,6 +10,7 @@ #include "command.h" #include "common.h" #include "common/logging.h" +#include "fe_utils/exit_codes.h" #include "input.h" #include "mainloop.h" #include "mb/pg_wchar.h" diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h index 73d4b393bc..506d6db0a4 100644 --- a/src/bin/psql/settings.h +++ b/src/bin/psql/settings.h @@ -157,17 +157,4 @@ typedef struct _psqlSettings extern PsqlSettings pset; - -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 -#endif - -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 -#endif - -#define EXIT_BADCONN 2 - -#define EXIT_USER 3 - #endif diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 5a28b6f713..877408f65b 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -19,6 +19,7 @@ #include "common/logging.h" #include "common/string.h" #include "describe.h" +#include "fe_utils/exit_codes.h" #include "fe_utils/print.h" #include "getopt_long.h" #include "help.h" diff --git a/src/include/fe_utils/exit_codes.h b/src/include/fe_utils/exit_codes.h new file mode 100644 index 0000000000..d7136f8b50 --- /dev/null +++ b/src/include/fe_utils/exit_codes.h @@ -0,0 +1,24 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright (c) 2000-2023, PostgreSQL Global Development Group + * + * src/include/fe_utils/exit_codes.h + */ + +#ifndef EXIT_CODES_H +#define EXIT_CODES_H + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif + +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif + +#define EXIT_BADCONN 2 + +#define EXIT_USER 3 + +#endif -- -- Tristan Partin Neon (https://neon.tech)
From b90da559dc27d671095ebafa9c805f1562029508 Mon Sep 17 00:00:00 2001 From: Tristan Partin <tris...@neon.tech> Date: Mon, 22 May 2023 08:19:27 -0500 Subject: [PATCH postgres v2 2/2] Add a post-PQcancel hook to setup_cancel_handler This is a follow-up to 1d468b9ad81b9139b4a0b16b416c3597925af4b0. This patch allowed pgbench to cancel server-side operations, but kept pgbench from exiting until the only CancelRequested check was evaluated. In addition, pgbench would not exit with a non-zero exit value given a SIGINT. --- src/bin/pg_amcheck/pg_amcheck.c | 2 +- src/bin/pgbench/pgbench.c | 17 +++++++++++++---- src/bin/scripts/clusterdb.c | 2 +- src/bin/scripts/reindexdb.c | 2 +- src/bin/scripts/vacuumdb.c | 2 +- src/fe_utils/cancel.c | 34 +++++++++++++++++++++++---------- src/include/fe_utils/cancel.h | 5 ++++- 7 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/bin/pg_amcheck/pg_amcheck.c b/src/bin/pg_amcheck/pg_amcheck.c index 68f8180c19..f3f31cde0f 100644 --- a/src/bin/pg_amcheck/pg_amcheck.c +++ b/src/bin/pg_amcheck/pg_amcheck.c @@ -470,7 +470,7 @@ main(int argc, char *argv[]) cparams.dbname = NULL; cparams.override_dbname = NULL; - setup_cancel_handler(NULL); + setup_cancel_handler(NULL, NULL); /* choose the database for our initial connection */ if (opts.alldb) diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 70ed034e70..b8568f47de 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -39,6 +39,7 @@ #include <math.h> #include <signal.h> #include <time.h> +#include <unistd.h> #include <sys/time.h> #include <sys/resource.h> /* for getrlimit */ @@ -60,6 +61,7 @@ #include "common/username.h" #include "fe_utils/cancel.h" #include "fe_utils/conditional.h" +#include "fe_utils/exit_codes.h" #include "fe_utils/option_utils.h" #include "fe_utils/string_utils.h" #include "getopt_long.h" @@ -4944,9 +4946,6 @@ initGenerateDataClientSide(PGconn *con) if (PQputline(con, sql.data)) pg_fatal("PQputline failed"); - if (CancelRequested) - break; - /* * If we want to stick with the original logging, print a message each * 100k inserted rows. @@ -5139,6 +5138,16 @@ checkInitSteps(const char *initialize_steps) } } +/* + * This function is called within a signal handler. Only use signal-safe + * functions. See signal-safety(7) for more information. + */ +static void +post_cancel_callback(void) +{ + _exit(EXIT_USER); +} + /* * Invoke each initialization step in the given string */ @@ -5156,7 +5165,7 @@ runInitSteps(const char *initialize_steps) if ((con = doConnect()) == NULL) pg_fatal("could not create connection for initialization"); - setup_cancel_handler(NULL); + setup_cancel_handler(NULL, post_cancel_callback); SetCancelConn(con); for (step = initialize_steps; *step != '\0'; step++) diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c index e3585b3272..f7a4785ec5 100644 --- a/src/bin/scripts/clusterdb.c +++ b/src/bin/scripts/clusterdb.c @@ -140,7 +140,7 @@ main(int argc, char *argv[]) cparams.prompt_password = prompt_password; cparams.override_dbname = NULL; - setup_cancel_handler(NULL); + setup_cancel_handler(NULL, NULL); if (alldb) { diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c index 3e8f6aca40..9a6af80f9e 100644 --- a/src/bin/scripts/reindexdb.c +++ b/src/bin/scripts/reindexdb.c @@ -201,7 +201,7 @@ main(int argc, char *argv[]) cparams.prompt_password = prompt_password; cparams.override_dbname = NULL; - setup_cancel_handler(NULL); + setup_cancel_handler(NULL, NULL); if (alldb) { diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index 687af9c1f3..4a49f83489 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -364,7 +364,7 @@ main(int argc, char *argv[]) cparams.prompt_password = prompt_password; cparams.override_dbname = NULL; - setup_cancel_handler(NULL); + setup_cancel_handler(NULL, NULL); /* Avoid opening extra connections. */ if (tbl_count && (concurrentCons > tbl_count)) diff --git a/src/fe_utils/cancel.c b/src/fe_utils/cancel.c index 10c0cd4554..dcefde9315 100644 --- a/src/fe_utils/cancel.c +++ b/src/fe_utils/cancel.c @@ -63,10 +63,14 @@ static CRITICAL_SECTION cancelConnLock; #endif /* - * Additional callback for cancellations. + * Additional callback for cancellations which is called prior to PQcancel. */ -static void (*cancel_callback) (void) = NULL; +static cancel_callback *pre_cancel_callback = NULL; +/* + * Additional callback for cancellations which is called after PQcancel. + */ +static cancel_callback *post_cancel_callback = NULL; /* * SetCancelConn @@ -157,8 +161,8 @@ handle_sigint(SIGNAL_ARGS) CancelRequested = true; - if (cancel_callback != NULL) - cancel_callback(); + if (pre_cancel_callback != NULL) + pre_cancel_callback(); /* Send QueryCancel if we are processing a database query */ if (cancelConn != NULL) @@ -174,6 +178,9 @@ handle_sigint(SIGNAL_ARGS) } } + if (post_cancel_callback != NULL) + post_cancel_callback(); + errno = save_errno; /* just in case the write changed it */ } @@ -183,9 +190,11 @@ handle_sigint(SIGNAL_ARGS) * Register query cancellation callback for SIGINT. */ void -setup_cancel_handler(void (*query_cancel_callback) (void)) +setup_cancel_handler(cancel_callback *query_pre_cancel_callback, + cancel_callback *query_post_cancel_callback) { - cancel_callback = query_cancel_callback; + pre_cancel_callback = query_pre_cancel_callback; + post_cancel_callback = query_post_cancel_callback; cancel_sent_msg = _("Cancel request sent\n"); cancel_not_sent_msg = _("Could not send cancel request: "); @@ -204,8 +213,8 @@ consoleHandler(DWORD dwCtrlType) { CancelRequested = true; - if (cancel_callback != NULL) - cancel_callback(); + if (pre_cancel_callback != NULL) + pre_cancel_callback(); /* Send QueryCancel if we are processing a database query */ EnterCriticalSection(&cancelConnLock); @@ -224,6 +233,9 @@ consoleHandler(DWORD dwCtrlType) LeaveCriticalSection(&cancelConnLock); + if (post_cancel_callback != NULL) + post_cancel_callback(); + return TRUE; } else @@ -232,9 +244,11 @@ consoleHandler(DWORD dwCtrlType) } void -setup_cancel_handler(void (*callback) (void)) +setup_cancel_handler(cancel_callback *query_pre_cancel_callback, + cancel_callback *query_post_cancel_callback) { - cancel_callback = callback; + pre_cancel_callback = query_pre_cancel_callback; + post_cancel_callback = query_post_cancel_callback; cancel_sent_msg = _("Cancel request sent\n"); cancel_not_sent_msg = _("Could not send cancel request: "); diff --git a/src/include/fe_utils/cancel.h b/src/include/fe_utils/cancel.h index 6e8b9ddfc4..0597186bed 100644 --- a/src/include/fe_utils/cancel.h +++ b/src/include/fe_utils/cancel.h @@ -18,6 +18,8 @@ #include "libpq-fe.h" +typedef void cancel_callback(void); + extern PGDLLIMPORT volatile sig_atomic_t CancelRequested; extern void SetCancelConn(PGconn *conn); @@ -27,6 +29,7 @@ extern void ResetCancelConn(void); * A callback can be optionally set up to be called at cancellation * time. */ -extern void setup_cancel_handler(void (*query_cancel_callback) (void)); +extern void setup_cancel_handler(cancel_callback *query_pre_cancel_callback, + cancel_callback *query_post_cancel_callback); #endif /* CANCEL_H */ -- -- Tristan Partin Neon (https://neon.tech)