aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/init/miscinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/init/miscinit.c')
-rw-r--r--src/backend/utils/init/miscinit.c72
1 files changed, 48 insertions, 24 deletions
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 0b004d7e5f0..85f1507ba36 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.176 2009/08/12 20:53:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.177 2009/08/27 16:59:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -683,7 +683,46 @@ CreateLockFile(const char *filename, bool amPostmaster,
int len;
int encoded_pid;
pid_t other_pid;
- pid_t my_pid = getpid();
+ pid_t my_pid,
+ my_p_pid,
+ my_gp_pid;
+ const char *envvar;
+
+ /*
+ * If the PID in the lockfile is our own PID or our parent's or
+ * grandparent's PID, then the file must be stale (probably left over from
+ * a previous system boot cycle). We need to check this because of the
+ * likelihood that a reboot will assign exactly the same PID as we had in
+ * the previous reboot, or one that's only one or two counts larger and
+ * hence the lockfile's PID now refers to an ancestor shell process. We
+ * allow pg_ctl to pass down its parent shell PID (our grandparent PID)
+ * via the environment variable PG_GRANDPARENT_PID; this is so that
+ * launching the postmaster via pg_ctl can be just as reliable as
+ * launching it directly. There is no provision for detecting
+ * further-removed ancestor processes, but if the init script is written
+ * carefully then all but the immediate parent shell will be root-owned
+ * processes and so the kill test will fail with EPERM. Note that we
+ * cannot get a false negative this way, because an existing postmaster
+ * would surely never launch a competing postmaster or pg_ctl process
+ * directly.
+ */
+ my_pid = getpid();
+
+#ifndef WIN32
+ my_p_pid = getppid();
+#else
+ /*
+ * Windows hasn't got getppid(), but doesn't need it since it's not
+ * using real kill() either...
+ */
+ my_p_pid = 0;
+#endif
+
+ envvar = getenv("PG_GRANDPARENT_PID");
+ if (envvar)
+ my_gp_pid = atoi(envvar);
+ else
+ my_gp_pid = 0;
/*
* We need a loop here because of race conditions. But don't loop forever
@@ -745,17 +784,11 @@ CreateLockFile(const char *filename, bool amPostmaster,
/*
* Check to see if the other process still exists
*
- * If the PID in the lockfile is our own PID or our parent's PID, then
- * the file must be stale (probably left over from a previous system
- * boot cycle). We need this test because of the likelihood that a
- * reboot will assign exactly the same PID as we had in the previous
- * reboot. Also, if there is just one more process launch in this
- * reboot than in the previous one, the lockfile might mention our
- * parent's PID. We can reject that since we'd never be launched
- * directly by a competing postmaster. We can't detect grandparent
- * processes unfortunately, but if the init script is written
- * carefully then all but the immediate parent shell will be
- * root-owned processes and so the kill test will fail with EPERM.
+ * Per discussion above, my_pid, my_p_pid, and my_gp_pid can be
+ * ignored as false matches.
+ *
+ * Normally kill() will fail with ESRCH if the given PID doesn't
+ * exist.
*
* We can treat the EPERM-error case as okay because that error
* implies that the existing process has a different userid than we
@@ -772,18 +805,9 @@ CreateLockFile(const char *filename, bool amPostmaster,
* Unix socket file belonging to an instance of Postgres being run by
* someone else, at least on machines where /tmp hasn't got a
* stickybit.)
- *
- * Windows hasn't got getppid(), but doesn't need it since it's not
- * using real kill() either...
- *
- * Normally kill() will fail with ESRCH if the given PID doesn't
- * exist.
*/
- if (other_pid != my_pid
-#ifndef WIN32
- && other_pid != getppid()
-#endif
- )
+ if (other_pid != my_pid && other_pid != my_p_pid &&
+ other_pid != my_gp_pid)
{
if (kill(other_pid, 0) == 0 ||
(errno != ESRCH && errno != EPERM))