diff options
Diffstat (limited to 'src/bin/psql/common.c')
-rw-r--r-- | src/bin/psql/common.c | 99 |
1 files changed, 87 insertions, 12 deletions
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 0ca6fa4f557..0089d5d2c81 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2004, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.92 2004/10/10 23:37:40 neilc Exp $ + * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.93 2004/10/30 23:10:50 tgl Exp $ */ #include "postgres_fe.h" #include "common.h" @@ -223,23 +223,33 @@ NoticeProcessor(void *arg, const char *message) * * Before we start a query, we enable a SIGINT signal catcher that sends a * cancel request to the backend. Note that sending the cancel directly from - * the signal handler is safe because PQrequestCancel() is written to make it - * so. We use write() to print to stdout because it's better to use simple + * the signal handler is safe because PQcancel() is written to make it + * so. We use write() to print to stderr because it's better to use simple * facilities in a signal handler. + * + * On win32, the signal cancelling happens on a separate thread, because + * that's how SetConsoleCtrlHandler works. The PQcancel function is safe + * for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required + * to protect the PGcancel structure against being changed while the other + * thread is using it. */ -static PGconn *volatile cancelConn = NULL; +static PGcancel *cancelConn = NULL; +#ifdef WIN32 +static CRITICAL_SECTION cancelConnLock; +#endif volatile bool cancel_pressed = false; +#define write_stderr(str) write(fileno(stderr), str, strlen(str)) -#ifndef WIN32 -#define write_stderr(String) write(fileno(stderr), String, strlen(String)) +#ifndef WIN32 void handle_sigint(SIGNAL_ARGS) { int save_errno = errno; + char errbuf[256]; /* Don't muck around if prompting for a password. */ if (prompt_state) @@ -250,17 +260,60 @@ handle_sigint(SIGNAL_ARGS) cancel_pressed = true; - if (PQrequestCancel(cancelConn)) + if (PQcancel(cancelConn, errbuf, sizeof(errbuf))) write_stderr("Cancel request sent\n"); else { write_stderr("Could not send cancel request: "); - write_stderr(PQerrorMessage(cancelConn)); + write_stderr(errbuf); } errno = save_errno; /* just in case the write changed it */ } -#endif /* not WIN32 */ +#else /* WIN32 */ + +static BOOL WINAPI +consoleHandler(DWORD dwCtrlType) +{ + char errbuf[256]; + + if (dwCtrlType == CTRL_C_EVENT || + dwCtrlType == CTRL_BREAK_EVENT) + { + if (prompt_state) + return TRUE; + + /* Perform query cancel */ + EnterCriticalSection(&cancelConnLock); + if (cancelConn != NULL) + { + cancel_pressed = true; + + if (PQcancel(cancelConn, errbuf, sizeof(errbuf))) + write_stderr("Cancel request sent\n"); + else + { + write_stderr("Could not send cancel request: "); + write_stderr(errbuf); + } + } + LeaveCriticalSection(&cancelConnLock); + + return TRUE; + } + else + /* Return FALSE for any signals not being handled */ + return FALSE; +} + +void +setup_cancel_handler(void) +{ + InitializeCriticalSection(&cancelConnLock); + SetConsoleCtrlHandler(consoleHandler, TRUE); +} + +#endif /* WIN32 */ /* ConnectionUp @@ -327,20 +380,42 @@ CheckConnection(void) static void SetCancelConn(void) { - cancelConn = pset.db; +#ifdef WIN32 + EnterCriticalSection(&cancelConnLock); +#endif + + /* Free the old one if we have one */ + if (cancelConn != NULL) + PQfreeCancel(cancelConn); + + cancelConn = PQgetCancel(pset.db); + +#ifdef WIN32 + LeaveCriticalSection(&cancelConnLock); +#endif } /* * ResetCancelConn * - * Set cancelConn to NULL. I don't know what this means exactly, but it saves - * having to export the variable. + * Free the current cancel connection, if any, and set to NULL. */ void ResetCancelConn(void) { +#ifdef WIN32 + EnterCriticalSection(&cancelConnLock); +#endif + + if (cancelConn) + PQfreeCancel(cancelConn); + cancelConn = NULL; + +#ifdef WIN32 + LeaveCriticalSection(&cancelConnLock); +#endif } |