mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
From: Tom Lane <tgl@sss.pgh.pa.us>
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:
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.92 1998/06/27 14:06:40 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.93 1998/07/09 03:28:47 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@@ -206,7 +206,6 @@ static int orgsigmask = sigblock(0);
|
||||
*/
|
||||
|
||||
static unsigned int random_seed = 0;
|
||||
long MyCancelKey = 0;
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind,
|
||||
@@ -228,7 +227,8 @@ static void ExitPostmaster(int status);
|
||||
static void usage(const char *);
|
||||
static int ServerLoop(void);
|
||||
static int BackendStartup(Port *port);
|
||||
static void readStartupPacket(char *arg, PacketLen len, char *pkt);
|
||||
static int readStartupPacket(void *arg, PacketLen len, void *pkt);
|
||||
static int processCancelRequest(Port *port, PacketLen len, void *pkt);
|
||||
static int initMasks(fd_set *rmask, fd_set *wmask);
|
||||
static long PostmasterRandom(void);
|
||||
static void RandomSalt(char *salt);
|
||||
@@ -518,6 +518,10 @@ PostmasterMain(int argc, char *argv[])
|
||||
if (silentflag)
|
||||
pmdaemonize();
|
||||
|
||||
/*
|
||||
* Set up signal handlers for the postmaster process.
|
||||
*/
|
||||
|
||||
pqsignal(SIGINT, pmdie);
|
||||
pqsignal(SIGCHLD, reaper);
|
||||
pqsignal(SIGTTIN, SIG_IGN);
|
||||
@@ -657,14 +661,14 @@ ServerLoop(void)
|
||||
(port = ConnCreate(ServerSock_UNIX)) != NULL)
|
||||
PacketReceiveSetup(&port->pktInfo,
|
||||
readStartupPacket,
|
||||
(char *) port);
|
||||
(void *) port);
|
||||
|
||||
if (ServerSock_INET != INVALID_SOCK &&
|
||||
FD_ISSET(ServerSock_INET, &rmask) &&
|
||||
(port = ConnCreate(ServerSock_INET)) != NULL)
|
||||
PacketReceiveSetup(&port->pktInfo,
|
||||
readStartupPacket,
|
||||
(char *) port);
|
||||
(void *) port);
|
||||
|
||||
/* Build up new masks for select(). */
|
||||
|
||||
@@ -790,8 +794,8 @@ initMasks(fd_set *rmask, fd_set *wmask)
|
||||
* Called when the startup packet has been read.
|
||||
*/
|
||||
|
||||
static void
|
||||
readStartupPacket(char *arg, PacketLen len, char *pkt)
|
||||
static int
|
||||
readStartupPacket(void *arg, PacketLen len, void *pkt)
|
||||
{
|
||||
Port *port;
|
||||
StartupPacket *si;
|
||||
@@ -799,6 +803,28 @@ readStartupPacket(char *arg, PacketLen len, char *pkt)
|
||||
port = (Port *) arg;
|
||||
si = (StartupPacket *) pkt;
|
||||
|
||||
/* The first field is either a protocol version number or
|
||||
* a special request code.
|
||||
*/
|
||||
|
||||
port->proto = ntohl(si->protoVersion);
|
||||
|
||||
if (port->proto == CANCEL_REQUEST_CODE)
|
||||
return processCancelRequest(port, len, pkt);
|
||||
|
||||
/* Could add additional special packet types here */
|
||||
|
||||
/* Check we can handle the protocol the frontend is using. */
|
||||
|
||||
if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
|
||||
PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
|
||||
(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
|
||||
PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
|
||||
{
|
||||
PacketSendError(&port->pktInfo, "Unsupported frontend protocol.");
|
||||
return STATUS_OK; /* don't close the connection yet */
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the parameters from the startup packet as C strings. The
|
||||
* packet destination was cleared first so a short packet has zeros
|
||||
@@ -815,31 +841,74 @@ readStartupPacket(char *arg, PacketLen len, char *pkt)
|
||||
if (port->database[0] == '\0')
|
||||
StrNCpy(port->database, si->user, sizeof(port->database) - 1);
|
||||
|
||||
/* Check we can handle the protocol the frontend is using. */
|
||||
|
||||
port->proto = ntohl(si->protoVersion);
|
||||
|
||||
if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
|
||||
PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
|
||||
(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
|
||||
PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
|
||||
{
|
||||
PacketSendError(&port->pktInfo, "Unsupported frontend protocol.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check a user name was given. */
|
||||
|
||||
if (port->user[0] == '\0')
|
||||
{
|
||||
PacketSendError(&port->pktInfo,
|
||||
"No Postgres username specified in startup packet.");
|
||||
return;
|
||||
return STATUS_OK; /* don't close the connection yet */
|
||||
}
|
||||
|
||||
/* Start the authentication itself. */
|
||||
|
||||
be_recvauth(port);
|
||||
|
||||
return STATUS_OK; /* don't close the connection yet */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The client has sent a cancel request packet, not a normal
|
||||
* start-a-new-backend packet. Perform the necessary processing.
|
||||
* Note that in any case, we return STATUS_ERROR to close the
|
||||
* connection immediately. Nothing is sent back to the client.
|
||||
*/
|
||||
|
||||
static int
|
||||
processCancelRequest(Port *port, PacketLen len, void *pkt)
|
||||
{
|
||||
CancelRequestPacket *canc = (CancelRequestPacket *) pkt;
|
||||
int backendPID;
|
||||
long cancelAuthCode;
|
||||
Dlelem *curr;
|
||||
Backend *bp;
|
||||
|
||||
backendPID = (int) ntohl(canc->backendPID);
|
||||
cancelAuthCode = (long) ntohl(canc->cancelAuthCode);
|
||||
|
||||
/* See if we have a matching backend */
|
||||
|
||||
for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
|
||||
{
|
||||
bp = (Backend *) DLE_VAL(curr);
|
||||
if (bp->pid == backendPID)
|
||||
{
|
||||
if (bp->cancel_key == cancelAuthCode)
|
||||
{
|
||||
/* Found a match; signal that backend to cancel current op */
|
||||
if (DebugLvl)
|
||||
fprintf(stderr, "%s: processCancelRequest: sending SIGINT to process %d\n",
|
||||
progname, bp->pid);
|
||||
kill(bp->pid, SIGINT);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Right PID, wrong key: no way, Jose */
|
||||
if (DebugLvl)
|
||||
fprintf(stderr, "%s: processCancelRequest: bad key in cancel request for process %d\n",
|
||||
progname, bp->pid);
|
||||
}
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* No matching backend */
|
||||
if (DebugLvl)
|
||||
fprintf(stderr, "%s: processCancelRequest: bad PID in cancel request for process %d\n",
|
||||
progname, backendPID);
|
||||
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -1221,6 +1290,8 @@ DoBackend(Port *port)
|
||||
char dbbuf[ARGV_SIZE + 1];
|
||||
int ac = 0;
|
||||
int i;
|
||||
struct timeval now;
|
||||
struct timezone tz;
|
||||
|
||||
/*
|
||||
* Let's clean up ourselves as the postmaster child
|
||||
@@ -1254,7 +1325,16 @@ DoBackend(Port *port)
|
||||
if (NetServer)
|
||||
StreamClose(ServerSock_INET);
|
||||
StreamClose(ServerSock_UNIX);
|
||||
|
||||
|
||||
/*
|
||||
* Don't want backend to be able to see the postmaster random number
|
||||
* generator state. We have to clobber the static random_seed *and*
|
||||
* start a new random sequence in the random() library function.
|
||||
*/
|
||||
random_seed = 0;
|
||||
gettimeofday(&now, &tz);
|
||||
srandom(now.tv_usec);
|
||||
|
||||
/* Now, on to standard postgres stuff */
|
||||
|
||||
MyProcPid = getpid();
|
||||
|
||||
Reference in New Issue
Block a user