PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
cancel.c
Go to the documentation of this file.
1/*------------------------------------------------------------------------
2 *
3 * Query cancellation support for frontend code
4 *
5 * Assorted utility functions to control query cancellation with signal
6 * handler for SIGINT.
7 *
8 *
9 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
11 *
12 * src/fe_utils/cancel.c
13 *
14 *------------------------------------------------------------------------
15 */
16
17#include "postgres_fe.h"
18
19#include <unistd.h>
20
21#include "common/connect.h"
22#include "fe_utils/cancel.h"
24
25
26/*
27 * Write a simple string to stderr --- must be safe in a signal handler.
28 * We ignore the write() result since there's not much we could do about it.
29 * Certain compilers make that harder than it ought to be.
30 */
31#define write_stderr(str) \
32 do { \
33 const char *str_ = (str); \
34 int rc_; \
35 rc_ = write(fileno(stderr), str_, strlen(str_)); \
36 (void) rc_; \
37 } while (0)
38
39/*
40 * Contains all the information needed to cancel a query issued from
41 * a database connection to the backend.
42 */
43static PGcancel *volatile cancelConn = NULL;
44
45/*
46 * Predetermined localized error strings --- needed to avoid trying
47 * to call gettext() from a signal handler.
48 */
49static const char *cancel_sent_msg = NULL;
50static const char *cancel_not_sent_msg = NULL;
51
52/*
53 * CancelRequested is set when we receive SIGINT (or local equivalent).
54 * There is no provision in this module for resetting it; but applications
55 * might choose to clear it after successfully recovering from a cancel.
56 * Note that there is no guarantee that we successfully sent a Cancel request,
57 * or that the request will have any effect if we did send it.
58 */
59volatile sig_atomic_t CancelRequested = false;
60
61#ifdef WIN32
62static CRITICAL_SECTION cancelConnLock;
63#endif
64
65/*
66 * Additional callback for cancellations.
67 */
68static void (*cancel_callback) (void) = NULL;
69
70
71/*
72 * SetCancelConn
73 *
74 * Set cancelConn to point to the current database connection.
75 */
76void
78{
79 PGcancel *oldCancelConn;
80
81#ifdef WIN32
82 EnterCriticalSection(&cancelConnLock);
83#endif
84
85 /* Free the old one if we have one */
86 oldCancelConn = cancelConn;
87
88 /* be sure handle_sigint doesn't use pointer while freeing */
89 cancelConn = NULL;
90
91 if (oldCancelConn != NULL)
92 PQfreeCancel(oldCancelConn);
93
95
96#ifdef WIN32
97 LeaveCriticalSection(&cancelConnLock);
98#endif
99}
100
101/*
102 * ResetCancelConn
103 *
104 * Free the current cancel connection, if any, and set to NULL.
105 */
106void
108{
109 PGcancel *oldCancelConn;
110
111#ifdef WIN32
112 EnterCriticalSection(&cancelConnLock);
113#endif
114
115 oldCancelConn = cancelConn;
116
117 /* be sure handle_sigint doesn't use pointer while freeing */
118 cancelConn = NULL;
119
120 if (oldCancelConn != NULL)
121 PQfreeCancel(oldCancelConn);
122
123#ifdef WIN32
124 LeaveCriticalSection(&cancelConnLock);
125#endif
126}
127
128
129/*
130 * Code to support query cancellation
131 *
132 * Note that sending the cancel directly from the signal handler is safe
133 * because PQcancel() is written to make it so. We use write() to report
134 * to stderr because it's better to use simple facilities in a signal
135 * handler.
136 *
137 * On Windows, the signal canceling happens on a separate thread, because
138 * that's how SetConsoleCtrlHandler works. The PQcancel function is safe
139 * for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required
140 * to protect the PGcancel structure against being changed while the signal
141 * thread is using it.
142 */
143
144#ifndef WIN32
145
146/*
147 * handle_sigint
148 *
149 * Handle interrupt signals by canceling the current command, if cancelConn
150 * is set.
151 */
152static void
154{
155 char errbuf[256];
156
157 CancelRequested = true;
158
159 if (cancel_callback != NULL)
161
162 /* Send QueryCancel if we are processing a database query */
163 if (cancelConn != NULL)
164 {
165 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
166 {
168 }
169 else
170 {
172 write_stderr(errbuf);
173 }
174 }
175}
176
177/*
178 * setup_cancel_handler
179 *
180 * Register query cancellation callback for SIGINT.
181 */
182void
183setup_cancel_handler(void (*query_cancel_callback) (void))
184{
185 cancel_callback = query_cancel_callback;
186 cancel_sent_msg = _("Cancel request sent\n");
187 cancel_not_sent_msg = _("Could not send cancel request: ");
188
189 pqsignal(SIGINT, handle_sigint);
190}
191
192#else /* WIN32 */
193
194static BOOL WINAPI
195consoleHandler(DWORD dwCtrlType)
196{
197 char errbuf[256];
198
199 if (dwCtrlType == CTRL_C_EVENT ||
200 dwCtrlType == CTRL_BREAK_EVENT)
201 {
202 CancelRequested = true;
203
204 if (cancel_callback != NULL)
206
207 /* Send QueryCancel if we are processing a database query */
208 EnterCriticalSection(&cancelConnLock);
209 if (cancelConn != NULL)
210 {
211 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
212 {
214 }
215 else
216 {
218 write_stderr(errbuf);
219 }
220 }
221
222 LeaveCriticalSection(&cancelConnLock);
223
224 return TRUE;
225 }
226 else
227 /* Return FALSE for any signals not being handled */
228 return FALSE;
229}
230
231void
232setup_cancel_handler(void (*callback) (void))
233{
235 cancel_sent_msg = _("Cancel request sent\n");
236 cancel_not_sent_msg = _("Could not send cancel request: ");
237
238 InitializeCriticalSection(&cancelConnLock);
239
240 SetConsoleCtrlHandler(consoleHandler, TRUE);
241}
242
243#endif /* WIN32 */
#define SIGNAL_ARGS
Definition: c.h:1320
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
static void(* cancel_callback)(void)
Definition: cancel.c:68
void ResetCancelConn(void)
Definition: cancel.c:107
static const char * cancel_sent_msg
Definition: cancel.c:49
void SetCancelConn(PGconn *conn)
Definition: cancel.c:77
static PGcancel *volatile cancelConn
Definition: cancel.c:43
#define write_stderr(str)
Definition: cancel.c:31
static const char * cancel_not_sent_msg
Definition: cancel.c:50
void setup_cancel_handler(void(*query_cancel_callback)(void))
Definition: cancel.c:183
static void handle_sigint(SIGNAL_ARGS)
Definition: cancel.c:153
#define _(x)
Definition: elog.c:90
PGcancel * PQgetCancel(PGconn *conn)
Definition: fe-cancel.c:349
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
Definition: fe-cancel.c:463
void PQfreeCancel(PGcancel *cancel)
Definition: fe-cancel.c:417
#define pqsignal
Definition: port.h:521
PGconn * conn
Definition: streamutil.c:52
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46