aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/libpq/pqcomm.c54
-rw-r--r--src/backend/postmaster/postmaster.c47
-rw-r--r--src/backend/utils/init/miscinit.c6
-rw-r--r--src/include/libpq/libpq.h1
4 files changed, 78 insertions, 30 deletions
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index b27ac952173..63673b16dfb 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -174,12 +174,15 @@ PQcommMethods *PqCommMethods = &PqCommSocketMethods;
void
pq_init(void)
{
+ /* initialize state variables */
PqSendBufferSize = PQ_SEND_BUFFER_SIZE;
PqSendBuffer = MemoryContextAlloc(TopMemoryContext, PqSendBufferSize);
PqSendPointer = PqSendStart = PqRecvPointer = PqRecvLength = 0;
PqCommBusy = false;
PqCommReadingMsg = false;
DoingCopyOut = false;
+
+ /* set up process-exit hook to close the socket */
on_proc_exit(socket_close, 0);
/*
@@ -285,28 +288,6 @@ socket_close(int code, Datum arg)
*/
-/* StreamDoUnlink()
- * Shutdown routine for backend connection
- * If any Unix sockets are used for communication, explicitly close them.
- */
-#ifdef HAVE_UNIX_SOCKETS
-static void
-StreamDoUnlink(int code, Datum arg)
-{
- ListCell *l;
-
- /* Loop through all created sockets... */
- foreach(l, sock_paths)
- {
- char *sock_path = (char *) lfirst(l);
-
- unlink(sock_path);
- }
- /* Since we're about to exit, no need to reclaim storage */
- sock_paths = NIL;
-}
-#endif /* HAVE_UNIX_SOCKETS */
-
/*
* StreamServerPort -- open a "listening" port to accept connections.
*
@@ -588,16 +569,11 @@ Lock_AF_UNIX(char *unixSocketDir, char *unixSocketPath)
* Once we have the interlock, we can safely delete any pre-existing
* socket file to avoid failure at bind() time.
*/
- unlink(unixSocketPath);
+ (void) unlink(unixSocketPath);
/*
- * Arrange to unlink the socket file(s) at proc_exit. If this is the
- * first one, set up the on_proc_exit function to do it; then add this
- * socket file to the list of files to unlink.
+ * Remember socket file pathnames for later maintenance.
*/
- if (sock_paths == NIL)
- on_proc_exit(StreamDoUnlink, 0);
-
sock_paths = lappend(sock_paths, pstrdup(unixSocketPath));
return STATUS_OK;
@@ -858,6 +834,26 @@ TouchSocketFiles(void)
}
}
+/*
+ * RemoveSocketFiles -- unlink socket files at postmaster shutdown
+ */
+void
+RemoveSocketFiles(void)
+{
+ ListCell *l;
+
+ /* Loop through all created sockets... */
+ foreach(l, sock_paths)
+ {
+ char *sock_path = (char *) lfirst(l);
+
+ /* Ignore any error. */
+ (void) unlink(sock_path);
+ }
+ /* Since we're about to exit, no need to reclaim storage */
+ sock_paths = NIL;
+}
+
/* --------------------------------
* Low-level I/O routines begin here.
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 1bb3138a03a..000524dcb94 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -370,6 +370,7 @@ static DNSServiceRef bonjour_sdref = NULL;
/*
* postmaster.c - function prototypes
*/
+static void CloseServerPorts(int status, Datum arg);
static void unlink_external_pid_file(int status, Datum arg);
static void getInstallationPaths(const char *argv0);
static void checkDataDir(void);
@@ -900,6 +901,11 @@ PostmasterMain(int argc, char *argv[])
* interlock (thanks to whoever decided to put socket files in /tmp :-().
* For the same reason, it's best to grab the TCP socket(s) before the
* Unix socket(s).
+ *
+ * Also note that this internally sets up the on_proc_exit function that
+ * is responsible for removing both data directory and socket lockfiles;
+ * so it must happen before opening sockets so that at exit, the socket
+ * lockfiles go away after CloseServerPorts runs.
*/
CreateDataDirLockFile(true);
@@ -924,10 +930,15 @@ PostmasterMain(int argc, char *argv[])
/*
* Establish input sockets.
+ *
+ * First, mark them all closed, and set up an on_proc_exit function that's
+ * charged with closing the sockets again at postmaster shutdown.
*/
for (i = 0; i < MAXLISTEN; i++)
ListenSocket[i] = PGINVALID_SOCKET;
+ on_proc_exit(CloseServerPorts, 0);
+
if (ListenAddresses)
{
char *rawstring;
@@ -1272,6 +1283,42 @@ PostmasterMain(int argc, char *argv[])
/*
+ * on_proc_exit callback to close server's listen sockets
+ */
+static void
+CloseServerPorts(int status, Datum arg)
+{
+ int i;
+
+ /*
+ * First, explicitly close all the socket FDs. We used to just let this
+ * happen implicitly at postmaster exit, but it's better to close them
+ * before we remove the postmaster.pid lockfile; otherwise there's a race
+ * condition if a new postmaster wants to re-use the TCP port number.
+ */
+ for (i = 0; i < MAXLISTEN; i++)
+ {
+ if (ListenSocket[i] != PGINVALID_SOCKET)
+ {
+ StreamClose(ListenSocket[i]);
+ ListenSocket[i] = PGINVALID_SOCKET;
+ }
+ }
+
+ /*
+ * Next, remove any filesystem entries for Unix sockets. To avoid race
+ * conditions against incoming postmasters, this must happen after closing
+ * the sockets and before removing lock files.
+ */
+ RemoveSocketFiles();
+
+ /*
+ * We don't do anything about socket lock files here; those will be
+ * removed in a later on_proc_exit callback.
+ */
+}
+
+/*
* on_proc_exit callback to delete external_pid_file
*/
static void
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index ac3e764e8b8..5bf595c9e5f 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -1018,7 +1018,11 @@ CreateLockFile(const char *filename, bool amPostmaster,
if (lock_files == NIL)
on_proc_exit(UnlinkLockFiles, 0);
- lock_files = lappend(lock_files, pstrdup(filename));
+ /*
+ * Use lcons so that the lock files are unlinked in reverse order of
+ * creation; this is critical!
+ */
+ lock_files = lcons(pstrdup(filename), lock_files);
}
/*
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index c408e5b5517..efb2dacbba3 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -59,6 +59,7 @@ extern int StreamServerPort(int family, char *hostName,
extern int StreamConnection(pgsocket server_fd, Port *port);
extern void StreamClose(pgsocket sock);
extern void TouchSocketFiles(void);
+extern void RemoveSocketFiles(void);
extern void pq_init(void);
extern int pq_getbytes(char *s, size_t len);
extern int pq_getstring(StringInfo s);