Consistently use "superuser" instead of "super user"
[pgsql.git] / src / fe_utils / cancel.c
blob14f939105ac84414d519c26c8ab1d50ceefd37d6
1 /*------------------------------------------------------------------------
3 * Query cancellation support for frontend code
5 * Assorted utility functions to control query cancellation with signal
6 * handler for SIGINT.
9 * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/fe-utils/cancel.c
14 *------------------------------------------------------------------------
17 #include "postgres_fe.h"
19 #include <unistd.h>
21 #include "common/connect.h"
22 #include "fe_utils/cancel.h"
23 #include "fe_utils/string_utils.h"
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.
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)
40 * Contains all the information needed to cancel a query issued from
41 * a database connection to the backend.
43 static PGcancel *volatile cancelConn = NULL;
46 * CancelRequested is set when we receive SIGINT (or local equivalent).
47 * There is no provision in this module for resetting it; but applications
48 * might choose to clear it after successfully recovering from a cancel.
49 * Note that there is no guarantee that we successfully sent a Cancel request,
50 * or that the request will have any effect if we did send it.
52 volatile sig_atomic_t CancelRequested = false;
54 #ifdef WIN32
55 static CRITICAL_SECTION cancelConnLock;
56 #endif
59 * Additional callback for cancellations.
61 static void (*cancel_callback) (void) = NULL;
65 * SetCancelConn
67 * Set cancelConn to point to the current database connection.
69 void
70 SetCancelConn(PGconn *conn)
72 PGcancel *oldCancelConn;
74 #ifdef WIN32
75 EnterCriticalSection(&cancelConnLock);
76 #endif
78 /* Free the old one if we have one */
79 oldCancelConn = cancelConn;
81 /* be sure handle_sigint doesn't use pointer while freeing */
82 cancelConn = NULL;
84 if (oldCancelConn != NULL)
85 PQfreeCancel(oldCancelConn);
87 cancelConn = PQgetCancel(conn);
89 #ifdef WIN32
90 LeaveCriticalSection(&cancelConnLock);
91 #endif
95 * ResetCancelConn
97 * Free the current cancel connection, if any, and set to NULL.
99 void
100 ResetCancelConn(void)
102 PGcancel *oldCancelConn;
104 #ifdef WIN32
105 EnterCriticalSection(&cancelConnLock);
106 #endif
108 oldCancelConn = cancelConn;
110 /* be sure handle_sigint doesn't use pointer while freeing */
111 cancelConn = NULL;
113 if (oldCancelConn != NULL)
114 PQfreeCancel(oldCancelConn);
116 #ifdef WIN32
117 LeaveCriticalSection(&cancelConnLock);
118 #endif
123 * Code to support query cancellation
125 * Note that sending the cancel directly from the signal handler is safe
126 * because PQcancel() is written to make it so. We use write() to report
127 * to stderr because it's better to use simple facilities in a signal
128 * handler.
130 * On Windows, the signal canceling happens on a separate thread, because
131 * that's how SetConsoleCtrlHandler works. The PQcancel function is safe
132 * for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required
133 * to protect the PGcancel structure against being changed while the signal
134 * thread is using it.
137 #ifndef WIN32
140 * handle_sigint
142 * Handle interrupt signals by canceling the current command, if cancelConn
143 * is set.
145 static void
146 handle_sigint(SIGNAL_ARGS)
148 int save_errno = errno;
149 char errbuf[256];
151 CancelRequested = true;
153 if (cancel_callback != NULL)
154 cancel_callback();
156 /* Send QueryCancel if we are processing a database query */
157 if (cancelConn != NULL)
159 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
161 write_stderr(_("Cancel request sent\n"));
163 else
165 write_stderr(_("Could not send cancel request: "));
166 write_stderr(errbuf);
170 errno = save_errno; /* just in case the write changed it */
174 * setup_cancel_handler
176 * Register query cancellation callback for SIGINT.
178 void
179 setup_cancel_handler(void (*callback) (void))
181 cancel_callback = callback;
182 pqsignal(SIGINT, handle_sigint);
185 #else /* WIN32 */
187 static BOOL WINAPI
188 consoleHandler(DWORD dwCtrlType)
190 char errbuf[256];
192 if (dwCtrlType == CTRL_C_EVENT ||
193 dwCtrlType == CTRL_BREAK_EVENT)
195 CancelRequested = true;
197 if (cancel_callback != NULL)
198 cancel_callback();
200 /* Send QueryCancel if we are processing a database query */
201 EnterCriticalSection(&cancelConnLock);
202 if (cancelConn != NULL)
204 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
206 write_stderr(_("Cancel request sent\n"));
208 else
210 write_stderr(_("Could not send cancel request: "));
211 write_stderr(errbuf);
215 LeaveCriticalSection(&cancelConnLock);
217 return TRUE;
219 else
220 /* Return FALSE for any signals not being handled */
221 return FALSE;
224 void
225 setup_cancel_handler(void (*callback) (void))
227 cancel_callback = callback;
229 InitializeCriticalSection(&cancelConnLock);
231 SetConsoleCtrlHandler(consoleHandler, TRUE);
234 #endif /* WIN32 */