PostgreSQL Source Code git master
Loading...
Searching...
No Matches
cancel.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------
2 *
3 * Query cancellation support for frontend code
4 *
5 * This module provides SIGINT/Ctrl-C handling for frontend tools that need to
6 * cancel queries or interrupt other operations. It provides three
7 * independent mechanisms, any combination of which can be used by an
8 * application:
9 *
10 * 1. Server cancel query request -- When a query is running and the main
11 * thread is waiting for the result of that query in a blocking manner, we
12 * want SIGINT/Ctrl-C to cancel that query. This can be achieved by
13 * calling SetCancelConn() to register the connection that is (or will be)
14 * running the query, prior to waiting for the result. When SIGINT/Ctrl-C
15 * is received, a cancel request for this connection will then be sent from
16 * the signal handler (on Windows, from a separate thread). That in turn
17 * will then (assuming a co-operating server) cause the server to cancel
18 * the query and send an error to the waiting client on the main thread.
19 * The cancel connection is a process-wide global, so only one connection
20 * can be the cancel target at a time. ResetCancelConn() should be called
21 * to disarm the mechanism again after the blocking wait has completed.
22 *
23 * 2. CancelRequested flag -- The CancelRequested flag is set to true whenever
24 * SIGINT is received, and can be checked by the application at appropriate
25 * times. The primary use case for this is when the application code is
26 * not blocked (indefinitely), but needs to take an action when Ctrl-C is
27 * pressed, such as break out of a long running loop.
28 *
29 * 3. Signal handler callback -- A callback function can be registered with
30 * setup_cancel_handler(), which will then be called directly from the
31 * signal handler whenever SIGINT is received. Because it is called from a
32 * signal handler, the callback function must be async-signal-safe. On
33 * Windows, it is called from a separate signal-handling thread. NOTE: The
34 * callback is called AFTER setting CancelRequested but BEFORE sending the
35 * cancel request to the server (if armed by SetCancelConn). This means
36 * that if the callback exits or longjmps, no cancel request will be sent
37 * to the server.
38 *
39 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
40 * Portions Copyright (c) 1994, Regents of the University of California
41 *
42 * src/fe_utils/cancel.c
43 *
44 *------------------------------------------------------------------------
45 */
46
47#include "postgres_fe.h"
48
49#include <unistd.h>
50
51#include "common/connect.h"
52#include "fe_utils/cancel.h"
54
55
56/*
57 * Write a simple string to stderr --- must be safe in a signal handler.
58 * We ignore the write() result since there's not much we could do about it.
59 * Certain compilers make that harder than it ought to be.
60 */
61#define write_stderr(str) \
62 do { \
63 const char *str_ = (str); \
64 ssize_t rc_; \
65 rc_ = write(fileno(stderr), str_, strlen(str_)); \
66 (void) rc_; \
67 } while (0)
68
69/*
70 * Contains all the information needed to cancel a query issued from
71 * a database connection to the backend.
72 */
73static PGcancel *volatile cancelConn = NULL;
74
75/*
76 * Predetermined localized error strings --- needed to avoid trying
77 * to call gettext() from a signal handler.
78 */
79static const char *cancel_sent_msg = NULL;
80static const char *cancel_not_sent_msg = NULL;
81
82/*
83 * CancelRequested is set when we receive SIGINT (or local equivalent).
84 * There is no provision in this module for resetting it; but applications
85 * might choose to clear it after successfully recovering from a cancel.
86 * Note that there is no guarantee that we successfully sent a Cancel request,
87 * or that the request will have any effect if we did send it.
88 */
90
91#ifdef WIN32
93#endif
94
95/*
96 * Additional callback for cancellations.
97 */
99
100
101/*
102 * SetCancelConn
103 *
104 * Set cancelConn to point to the current database connection.
105 */
106void
108{
110
111#ifdef WIN32
113#endif
114
115 /* Free the old one if we have one */
117
118 /* be sure handle_sigint doesn't use pointer while freeing */
120
121 if (oldCancelConn != NULL)
123
125
126#ifdef WIN32
128#endif
129}
130
131/*
132 * ResetCancelConn
133 *
134 * Free the current cancel connection, if any, and set to NULL.
135 */
136void
138{
140
141#ifdef WIN32
143#endif
144
146
147 /* be sure handle_sigint doesn't use pointer while freeing */
149
150 if (oldCancelConn != NULL)
152
153#ifdef WIN32
155#endif
156}
157
158
159/*
160 * Code to support query cancellation
161 *
162 * Note that sending the cancel directly from the signal handler is safe
163 * because PQcancel() is written to make it so. We use write() to report
164 * to stderr because it's better to use simple facilities in a signal
165 * handler.
166 *
167 * On Windows, the signal canceling happens on a separate thread, because
168 * that's how SetConsoleCtrlHandler works. The PQcancel function is safe
169 * for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required
170 * to protect the PGcancel structure against being changed while the signal
171 * thread is using it.
172 */
173
174#ifndef WIN32
175
176/*
177 * handle_sigint
178 *
179 * Handle interrupt signals by canceling the current command, if cancelConn
180 * is set.
181 */
182static void
184{
185 char errbuf[256];
186
187 CancelRequested = true;
188
189 if (cancel_callback != NULL)
191
192 /* Send QueryCancel if we are processing a database query */
193 if (cancelConn != NULL)
194 {
195 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
196 {
198 }
199 else
200 {
202 write_stderr(errbuf);
203 }
204 }
205}
206
207/*
208 * setup_cancel_handler
209 *
210 * Register query cancellation callback for SIGINT.
211 */
212void
214{
216 cancel_sent_msg = _("Cancel request sent\n");
217 cancel_not_sent_msg = _("Could not send cancel request: ");
218
220}
221
222#else /* WIN32 */
223
224static BOOL WINAPI
226{
227 char errbuf[256];
228
229 if (dwCtrlType == CTRL_C_EVENT ||
231 {
232 CancelRequested = true;
233
234 if (cancel_callback != NULL)
236
237 /* Send QueryCancel if we are processing a database query */
239 if (cancelConn != NULL)
240 {
241 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
242 {
244 }
245 else
246 {
248 write_stderr(errbuf);
249 }
250 }
251
253
254 return TRUE;
255 }
256 else
257 /* Return FALSE for any signals not being handled */
258 return FALSE;
259}
260
261void
262setup_cancel_handler(void (*callback) (void))
263{
265 cancel_sent_msg = _("Cancel request sent\n");
266 cancel_not_sent_msg = _("Could not send cancel request: ");
267
269
271}
272
273#endif /* WIN32 */
#define SIGNAL_ARGS
Definition c.h:1519
volatile sig_atomic_t CancelRequested
Definition cancel.c:89
static void(* cancel_callback)(void)
Definition cancel.c:98
void ResetCancelConn(void)
Definition cancel.c:137
static const char * cancel_sent_msg
Definition cancel.c:79
void SetCancelConn(PGconn *conn)
Definition cancel.c:107
static PGcancel *volatile cancelConn
Definition cancel.c:73
#define write_stderr(str)
Definition cancel.c:61
static const char * cancel_not_sent_msg
Definition cancel.c:80
void setup_cancel_handler(void(*query_cancel_callback)(void))
Definition cancel.c:213
static void handle_sigint(SIGNAL_ARGS)
Definition cancel.c:183
#define _(x)
Definition elog.c:96
PGcancel * PQgetCancel(PGconn *conn)
Definition fe-cancel.c:368
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
Definition fe-cancel.c:548
void PQfreeCancel(PGcancel *cancel)
Definition fe-cancel.c:502
#define pqsignal
Definition port.h:548
static int fb(int x)
PGconn * conn
Definition streamutil.c:52
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)