1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00
Making PQrequestCancel safe to call in a signal handler turned out to be
much easier than I feared.  So here are the diffs.

Some notes:
  * I modified the postmaster's packet "iodone" callback interface to allow
    the callback routine to return a continue-or-drop-connection return
    code; this was necessary to allow the connection to be closed after
    receiving a Cancel, rather than proceeding to launch a new backend...
    Being a neatnik, I also made the iodone proc have a typechecked
    parameter list.
  * I deleted all code I could find that had to do with OOB.
  * I made some edits to ensure that all signals mentioned in the code
    are referred to symbolically not by numbers ("SIGUSR2" not "2").
    I think Bruce may have already done at least some of the same edits;
    I hope that merging these patches is not too painful.
This commit is contained in:
Marc G. Fournier
1998-07-09 03:29:11 +00:00
parent 8bf61820f0
commit a0659e3e2c
20 changed files with 597 additions and 287 deletions

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.72 1998/07/07 18:00:09 scrappy Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.73 1998/07/09 03:29:07 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@ -499,13 +499,11 @@ connectDB(PGconn *conn)
{
PGresult *res;
struct hostent *hp;
StartupPacket sp;
AuthRequest areq;
int laddrlen = sizeof(SockAddr);
int portno,
family,
len;
family;
char beresp;
int on = 1;
@ -561,11 +559,11 @@ connectDB(PGconn *conn)
(char *) hp->h_addr,
hp->h_length);
conn->raddr.in.sin_port = htons((unsigned short) (portno));
len = sizeof(struct sockaddr_in);
conn->raddr_len = sizeof(struct sockaddr_in);
}
#ifndef WIN32
else
len = UNIXSOCK_PATH(conn->raddr.un, portno);
conn->raddr_len = UNIXSOCK_PATH(conn->raddr.un, portno);
#endif
@ -577,7 +575,7 @@ connectDB(PGconn *conn)
errno, strerror(errno));
goto connect_errReturn;
}
if (connect(conn->sock, &conn->raddr.sa, len) < 0)
if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
{
(void) sprintf(conn->errorMessage,
"connectDB() failed: Is the postmaster running and accepting%s connections at '%s' on port '%s'?\n",
@ -724,7 +722,7 @@ connectDB(PGconn *conn)
* A ReadyForQuery message indicates that startup is successful,
* but we might also get an Error message indicating failure.
* (Notice messages indicating nonfatal warnings are also allowed
* by the protocol.)
* by the protocol, as is a BackendKeyData message.)
* Easiest way to handle this is to let PQgetResult() read the messages.
* We just have to fake it out about the state of the connection.
*/
@ -994,6 +992,99 @@ PQreset(PGconn *conn)
}
}
/*
* PQrequestCancel: attempt to request cancellation of the current operation.
*
* The return value is TRUE if the cancel request was successfully
* dispatched, FALSE if not (in which case errorMessage is set).
* Note: successful dispatch is no guarantee that there will be any effect at
* the backend. The application must read the operation result as usual.
*
* CAUTION: we want this routine to be safely callable from a signal handler
* (for example, an application might want to call it in a SIGINT handler).
* This means we cannot use any C library routine that might be non-reentrant.
* malloc/free are often non-reentrant, and anything that might call them is
* just as dangerous. We avoid sprintf here for that reason. Building up
* error messages with strcpy/strcat is tedious but should be quite safe.
*/
int
PQrequestCancel(PGconn *conn)
{
int tmpsock = -1;
struct {
uint32 packetlen;
CancelRequestPacket cp;
} crp;
/* Check we have an open connection */
if (!conn)
return FALSE;
if (conn->sock < 0)
{
strcpy(conn->errorMessage,
"PQrequestCancel() -- connection is not open\n");
return FALSE;
}
/*
* We need to open a temporary connection to the postmaster.
* Use the information saved by connectDB to do this with
* only kernel calls.
*/
if ((tmpsock = socket(conn->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
{
strcpy(conn->errorMessage, "PQrequestCancel() -- socket() failed: ");
goto cancel_errReturn;
}
if (connect(tmpsock, &conn->raddr.sa, conn->raddr_len) < 0)
{
strcpy(conn->errorMessage, "PQrequestCancel() -- connect() failed: ");
goto cancel_errReturn;
}
/*
* We needn't set nonblocking I/O or NODELAY options here.
*/
/* Create and send the cancel request packet. */
crp.packetlen = htonl((uint32) sizeof(crp));
crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);
crp.cp.backendPID = htonl(conn->be_pid);
crp.cp.cancelAuthCode = htonl(conn->be_key);
if (send(tmpsock, (char*) &crp, sizeof(crp), 0) != (int) sizeof(crp))
{
strcpy(conn->errorMessage, "PQrequestCancel() -- send() failed: ");
goto cancel_errReturn;
}
/* Sent it, done */
#ifdef WIN32
closesocket(tmpsock);
#else
close(tmpsock);
#endif
return TRUE;
cancel_errReturn:
strcat(conn->errorMessage, strerror(errno));
strcat(conn->errorMessage, "\n");
if (tmpsock >= 0)
{
#ifdef WIN32
closesocket(tmpsock);
#else
close(tmpsock);
#endif
}
return FALSE;
}
/*
* PacketSend() -- send a single-packet message.
* this is like PacketSend(), defined in backend/libpq/pqpacket.c