93d352
diff -up db-5.3.28/dist/android/android_config.in.pthreads db-5.3.28/dist/android/android_config.in
93d352
--- db-5.3.28/dist/android/android_config.in.pthreads	2013-09-09 17:35:02.000000000 +0200
93d352
+++ db-5.3.28/dist/android/android_config.in	2017-06-13 11:15:15.323215161 +0200
93d352
@@ -123,6 +123,9 @@
93d352
 /* Define to 1 if allocated filesystem blocks are not zeroed. */
93d352
 /* #undef HAVE_FILESYSTEM_NOTZERO */
93d352
 
93d352
+/* Define to 1 if you have the `flock' function. */
93d352
+#undef HAVE_FLOCK
93d352
+
93d352
 /* Define to 1 if you have the `fopen' function. */
93d352
 #define HAVE_FOPEN 1
93d352
 
93d352
diff -up db-5.3.28/dist/config.hin.pthreads db-5.3.28/dist/config.hin
93d352
--- db-5.3.28/dist/config.hin.pthreads	2013-09-09 17:35:02.000000000 +0200
93d352
+++ db-5.3.28/dist/config.hin	2017-06-13 11:15:15.000000000 +0200
93d352
@@ -92,6 +92,9 @@
93d352
 /* Define to 1 if you have the <dlfcn.h> header file. */
93d352
 #undef HAVE_DLFCN_H
93d352
 
93d352
+/* Define to 1 if you have the `dl_iterate_phdr' function. */
93d352
+#undef HAVE_DL_ITERATE_PHDR
93d352
+
93d352
 /* Define to 1 to use dtrace for performance monitoring. */
93d352
 #undef HAVE_DTRACE
93d352
 
93d352
@@ -125,6 +128,9 @@
93d352
 /* Define to 1 if allocated filesystem blocks are not zeroed. */
93d352
 #undef HAVE_FILESYSTEM_NOTZERO
93d352
 
93d352
+/* Define to 1 if you have the `flock' function. */
93d352
+#undef HAVE_FLOCK
93d352
+
93d352
 /* Define to 1 if you have the `fopen' function. */
93d352
 #undef HAVE_FOPEN
93d352
 
93d352
@@ -360,6 +366,9 @@
93d352
 /* Define to 1 if you have the `pstat_getdynamic' function. */
93d352
 #undef HAVE_PSTAT_GETDYNAMIC
93d352
 
93d352
+/* Define to 1 if you have dl_iterate_phdr and use pthread-based mutexes. */
93d352
+#undef HAVE_PTHREADS_TIMESTAMP
93d352
+
93d352
 /* Define to 1 if it is OK to initialize an already initialized
93d352
    pthread_cond_t. */
93d352
 #undef HAVE_PTHREAD_COND_REINIT_OKAY
93d352
@@ -620,6 +629,11 @@
93d352
 /* Define to 1 to mask harmless uninitialized memory read/writes. */
93d352
 #undef UMRW
93d352
 
93d352
+/* Enable large inode numbers on Mac OS X 10.5.  */
93d352
+#ifndef _DARWIN_USE_64_BIT_INODE
93d352
+# define _DARWIN_USE_64_BIT_INODE 1
93d352
+#endif
93d352
+
93d352
 /* Number of bits in a file offset, on hosts where this is settable. */
93d352
 #undef _FILE_OFFSET_BITS
93d352
 
93d352
diff -up db-5.3.28/dist/configure.ac.pthreads db-5.3.28/dist/configure.ac
93d352
--- db-5.3.28/dist/configure.ac.pthreads	2017-06-13 11:15:15.309215434 +0200
93d352
+++ db-5.3.28/dist/configure.ac	2017-06-13 11:15:15.323215161 +0200
93d352
@@ -698,7 +698,7 @@ AC_REPLACE_FUNCS(\
93d352
 # Check for system functions we optionally use.
93d352
 AC_CHECK_FUNCS(\
93d352
 	_fstati64 backtrace backtrace_symbols directio fchmod fclose\
93d352
-	fcntl fdatasync fgetc fgets fopen fwrite getgid\
93d352
+	fcntl fdatasync fgetc fgets flock fopen fwrite getgid\
93d352
 	getrusage getuid hstrerror mprotect pstat_getdynamic\
93d352
 	pthread_self pthread_yield random sched_yield select setgid setuid\
93d352
 	sigaction snprintf stat sysconf vsnprintf yield)
93d352
@@ -1042,6 +1042,34 @@ if test "$db_cv_localization" = "yes"; t
93d352
 [Define to 1 if you have localization function to support globalization.])
93d352
 fi
93d352
 
93d352
+# Check for dl_iterate_phdr; do the test explicitly instead of using
93d352
+# AC_CHECK_FUNCS because <netdb.h> isn't a standard include file.
93d352
+AC_CACHE_CHECK([for dl_iterate_phdr], db_cv_dl_iterate_phdr, [
93d352
+AC_TRY_LINK([
93d352
+#include <sys/types.h>
93d352
+#include <netdb.h>], [
93d352
+	dl_iterate_phdr(0, 0);
93d352
+], [db_cv_dl_iterate_phdr=yes], [db_cv_dl_iterate_phdr=no])])
93d352
+if test "$db_cv_dl_iterate_phdr" = "yes"; then
93d352
+	AC_DEFINE(HAVE_DL_ITERATE_PHDR)
93d352
+	AH_TEMPLATE(HAVE_DL_ITERATE_PHDR,
93d352
+	    [Define to 1 if you have the `dl_iterate_phdr' function.])
93d352
+fi
93d352
+ 
93d352
+# If we are using pthread mutex or condition variables, and dl_iterate_phdr() is 
93d352
+# available, then we try to detect when libpthread is updated -- which can
93d352
+# render existing environment invalid.   DB_ENV->open() tries to rebuild such
93d352
+# environments when they are idle.
93d352
+case "$db_cv_mutex" in
93d352
+    *pthreads*)
93d352
+    if test "$db_cv_dl_iterate_phdr" = "yes" ; then
93d352
+	AC_DEFINE(HAVE_PTHREADS_TIMESTAMP)
93d352
+	AH_TEMPLATE(HAVE_PTHREADS_TIMESTAMP,
93d352
+     [Define to 1 if you have dl_iterate_phdr and use pthread-based mutexes.])
93d352
+    fi
93d352
+    ;;
93d352
+esac
93d352
+
93d352
 # We need to add the additional object files into the Makefile with the correct
93d352
 # suffix.  We can't use $LTLIBOBJS itself, because that variable has $U encoded
93d352
 # in it for automake, and that's not what we want.  See SR #7227 for additional
93d352
diff -up db-5.3.28/src/db/db_meta.c.pthreads db-5.3.28/src/db/db_meta.c
93d352
--- db-5.3.28/src/db/db_meta.c.pthreads	2013-09-09 17:35:07.000000000 +0200
93d352
+++ db-5.3.28/src/db/db_meta.c	2017-06-13 11:15:15.323215161 +0200
93d352
@@ -1330,8 +1330,9 @@ __db_haslock(env, locker, dbmfp, pgno, m
93d352
 }
93d352
 /*
93d352
  * __db_has_pagelock --
93d352
- *	Determine if this locker holds a particular page lock.
93d352
- *	Returns 0 if lock is held, non-zero otherwise.
93d352
+ *	Determine if this locker holds a particular page lock, and return an
93d352
+ *	error if it is missing a page lock that it should have.
93d352
+ *	Otherwise (TDS with the page locked, or DS or CDS) return 0.
93d352
  *
93d352
  * PUBLIC: #ifdef DIAGNOSTIC
93d352
  * PUBLIC: int __db_has_pagelock __P((ENV *, DB_LOCKER *,
93d352
@@ -1348,6 +1349,9 @@ __db_has_pagelock(env, locker, dbmfp, pa
93d352
 {
93d352
 	int ret;
93d352
 
93d352
+	if (!FLD_ISSET(env->open_flags, DB_INIT_TXN))
93d352
+		return (0);
93d352
+
93d352
 	switch (pagep->type) {
93d352
 	case P_OVERFLOW:
93d352
 	case P_INVALID:
93d352
diff -up db-5.3.28/src/dbinc_auto/int_def.in.pthreads db-5.3.28/src/dbinc_auto/int_def.in
93d352
--- db-5.3.28/src/dbinc_auto/int_def.in.pthreads	2017-06-13 11:15:15.317215278 +0200
93d352
+++ db-5.3.28/src/dbinc_auto/int_def.in	2017-06-13 11:15:15.324215141 +0200
93d352
@@ -1545,6 +1545,7 @@
93d352
 #if defined(HAVE_REPLICATION_THREADS)
93d352
 #define	__os_freeaddrinfo __os_freeaddrinfo@DB_VERSION_UNIQUE_NAME@
93d352
 #endif
93d352
+#define	__os_pthreads_timestamp __os_pthreads_timestamp@DB_VERSION_UNIQUE_NAME@
93d352
 #define	__os_umalloc __os_umalloc@DB_VERSION_UNIQUE_NAME@
93d352
 #define	__os_urealloc __os_urealloc@DB_VERSION_UNIQUE_NAME@
93d352
 #define	__os_ufree __os_ufree@DB_VERSION_UNIQUE_NAME@
93d352
diff -up db-5.3.28/src/dbinc_auto/os_ext.h.pthreads db-5.3.28/src/dbinc_auto/os_ext.h
93d352
--- db-5.3.28/src/dbinc_auto/os_ext.h.pthreads	2013-09-09 17:35:08.000000000 +0200
93d352
+++ db-5.3.28/src/dbinc_auto/os_ext.h	2017-06-13 11:15:15.324215141 +0200
93d352
@@ -14,6 +14,7 @@ int __os_getaddrinfo __P((ENV *, const c
93d352
 #if defined(HAVE_REPLICATION_THREADS)
93d352
 void __os_freeaddrinfo __P((ENV *, ADDRINFO *));
93d352
 #endif
93d352
+time_t __os_pthreads_timestamp __P((ENV *));
93d352
 int __os_umalloc __P((ENV *, size_t, void *));
93d352
 int __os_urealloc __P((ENV *, size_t, void *));
93d352
 void __os_ufree __P((ENV *, void *));
93d352
@@ -40,7 +41,7 @@ void __os_set_errno __P((int));
93d352
 char *__os_strerror __P((int, char *, size_t));
93d352
 int __os_posix_err __P((int));
93d352
 int __os_fileid __P((ENV *, const char *, int, u_int8_t *));
93d352
-int __os_fdlock __P((ENV *, DB_FH *, off_t, int, int));
93d352
+int __os_fdlock __P((ENV *, DB_FH *, off_t, db_lockmode_t, int));
93d352
 int __os_fsync __P((ENV *, DB_FH *));
93d352
 int __os_getenv __P((ENV *, const char *, char **, size_t));
93d352
 int __os_openhandle __P((ENV *, const char *, int, int, DB_FH **));
93d352
diff -up db-5.3.28/src/dbinc/region.h.pthreads db-5.3.28/src/dbinc/region.h
93d352
--- db-5.3.28/src/dbinc/region.h.pthreads	2013-09-09 17:35:08.000000000 +0200
93d352
+++ db-5.3.28/src/dbinc/region.h	2017-06-13 11:15:15.324215141 +0200
93d352
@@ -178,6 +178,16 @@ typedef struct __db_reg_env { /* SHARED
93d352
 	u_int32_t envid;		/* Unique environment ID. */
93d352
 
93d352
 	u_int32_t signature;		/* Structure signatures. */
93d352
+#if defined(HAVE_PTHREADS_TIMESTAMP) && defined(HAVE_MUTEX_PTHREADS)
93d352
+	/*
93d352
+	 * Updates to glibc/libpthread can change its pthreads implementation
93d352
+	 * and invalidate on-disk environments, even without changing the
93d352
+	 * version number.  If using POSIX mutexes and a change in this
93d352
+	 * timestamp is detecting when opening an environment with DB_CREATE,
93d352
+	 *  __env_attach recreates any existing on-disk environment.
93d352
+	 */
93d352
+	time_t pthreads_timestamp;
93d352
+#endif
93d352
 
93d352
 	time_t	  timestamp;		/* Creation time. */
93d352
 
93d352
diff -up db-5.3.28/src/env/env_open.c.pthreads db-5.3.28/src/env/env_open.c
93d352
--- db-5.3.28/src/env/env_open.c.pthreads	2013-09-09 17:35:08.000000000 +0200
93d352
+++ db-5.3.28/src/env/env_open.c	2017-06-13 11:15:15.324215141 +0200
93d352
@@ -1031,11 +1031,11 @@ __env_attach_regions(dbenv, flags, orig_
93d352
 		goto err;
93d352
 
93d352
 	/*
93d352
-	 * __env_attach will return the saved init_flags field, which contains
93d352
+	 * __env_attach has returned the saved init_flags field, which contains
93d352
 	 * the DB_INIT_* flags used when the environment was created.
93d352
 	 *
93d352
-	 * We may be joining an environment -- reset our flags to match the
93d352
-	 * ones in the environment.
93d352
+	 * We may be joining an existing environment -- reset our flags to match
93d352
+	 * the ones in the environment.
93d352
 	 */
93d352
 	if (FLD_ISSET(init_flags, DB_INITENV_CDB))
93d352
 		LF_SET(DB_INIT_CDB);
93d352
diff -up db-5.3.28/src/env/env_region.c.pthreads db-5.3.28/src/env/env_region.c
93d352
--- db-5.3.28/src/env/env_region.c.pthreads	2013-09-09 17:35:08.000000000 +0200
93d352
+++ db-5.3.28/src/env/env_region.c	2017-06-13 11:16:02.159299222 +0200
93d352
@@ -18,13 +18,49 @@ static int  __env_des_get __P((ENV *, RE
93d352
 static int  __env_faultmem __P((ENV *, void *, size_t, int));
93d352
 static int  __env_sys_attach __P((ENV *, REGINFO *, REGION *));
93d352
 static int  __env_sys_detach __P((ENV *, REGINFO *, int));
93d352
+static int  __env_check_recreate __P((ENV *, REGENV *, u_int32_t));
93d352
 static void __env_des_destroy __P((ENV *, REGION *));
93d352
 static void __env_remove_file __P((ENV *));
93d352
 
93d352
+
93d352
+/*
93d352
+ * If the system supports flock()-like file locking, then the primary region
93d352
+ * file __db.001 is exclusively locked during creation, and is read-locked while
93d352
+ * the environment is open. Most Unix-like systems have flock(), with the
93d352
+ * notable exception of Solaris.
93d352
+ * Note: fcntl cannot be used for this locking because of the unfortunate
93d352
+ * definition of its interaction with close(2). A process's fcntl locks are
93d352
+ * released whenever it closes any file descriptor for that file. So, if an
93d352
+ * environment is opened more than once, closing one of the DB_ENV handles would
93d352
+ * release the read lock that protects the other handle.
93d352
+ */
93d352
+#ifdef HAVE_FLOCK
93d352
+#define ENV_PRIMARY_LOCK(env, lockmode, async)	\
93d352
+	((env)->lockfhp == NULL ? 0 :	\
93d352
+	__os_fdlock((env), (env)->lockfhp, -1, lockmode, async))
93d352
+#define ENV_PRIMARY_UNLOCK(env)			\
93d352
+	((env)->lockfhp == NULL ? 0 :	\
93d352
+	__os_fdlock((env), (env)->lockfhp, -1, DB_LOCK_NG, 0))
93d352
+#else
93d352
+#define ENV_PRIMARY_LOCK(env, lockmode, async)	(0)
93d352
+#define ENV_PRIMARY_UNLOCK(env)			(0)
93d352
+#endif
93d352
+
93d352
 /*
93d352
  * __env_attach
93d352
  *	Join/create the environment
93d352
  *
93d352
+ * Safely detecting and managing multiple processes' environment handles:
93d352
+ *	BDB uses a shared or exclusive fcntl()-style lock on the first byte
93d352
+ *	of the primary region file (__db.001) to detect whether other processes
93d352
+ *	have the environment open, and to single-thread attempts to create the
93d352
+ *	environment.  If the open includes DB_CREATE, an exclusive lock is
93d352
+ *	obtained during the open call.  After the creation is finished, and
93d352
+ *	anytime during a non-DB_CREATE env open, the process holds a shared
93d352
+ *	lock. 
93d352
+ *	- single-thread creation of the environment
93d352
+ *	- detect whether any other processes are currently attached to it.
93d352
+ *
93d352
  * PUBLIC: int __env_attach __P((ENV *, u_int32_t *, int, int));
93d352
  */
93d352
 int
93d352
@@ -122,7 +158,11 @@ loop:	renv = NULL;
93d352
 	if ((ret = __os_open(
93d352
 	    env, infop->name, 0, DB_OSO_REGION, 0, &env->lockfhp)) != 0)
93d352
 		goto err;
93d352
-
93d352
+	/* Wait to get shared access to the primary region. */
93d352
+	if ((ret = ENV_PRIMARY_LOCK(env, DB_LOCK_READ, 0)) != 0) {
93d352
+		__db_err(env, ret, "__env_attach: existing: shared lock error");
93d352
+		goto err;
93d352
+	}
93d352
 	/*
93d352
 	 * !!!
93d352
 	 * The region may be in system memory not backed by the filesystem
93d352
@@ -218,11 +258,10 @@ loop:	renv = NULL;
93d352
 		segid = ref.segid;
93d352
 	}
93d352
 
93d352
-#ifndef HAVE_MUTEX_FCNTL
93d352
+#if !defined(HAVE_FCNTL) && !defined(HAVE_PTHREADS_TIMESTAMP)
93d352
 	/*
93d352
-	 * If we're not doing fcntl locking, we can close the file handle.  We
93d352
-	 * no longer need it and the less contact between the buffer cache and
93d352
-	 * the VM, the better.
93d352
+	 * Without fcntl-like support, we no longer need the file handle.  Close
93d352
+	 * it to limit the interaction between the buffer cache and the VM.
93d352
 	 */
93d352
 	(void)__os_closehandle(env, env->lockfhp);
93d352
 	 env->lockfhp = NULL;
93d352
@@ -233,6 +272,8 @@ loop:	renv = NULL;
93d352
 	tregion.size = (roff_t)size;
93d352
 	tregion.max = (roff_t)max;
93d352
 	tregion.segid = segid;
93d352
+	/* Attach to the existing primary region. */
93d352
+	/* The leaking db.001 gets open inside of here, in __os_attach(). */
93d352
 	if ((ret = __env_sys_attach(env, infop, &tregion)) != 0)
93d352
 		goto err;
93d352
 
93d352
@@ -245,21 +286,48 @@ user_map_functions:
93d352
 	infop->primary = infop->addr;
93d352
 	infop->head = (u_int8_t *)infop->addr + sizeof(REGENV);
93d352
 	renv = infop->primary;
93d352
+    ret = __env_check_recreate(env, renv, signature);
93d352
+
93d352
+	if (create_ok &&
93d352
+	    ret == DB_OLD_VERSION &&
93d352
+	    ENV_PRIMARY_LOCK(env, DB_LOCK_WRITE, 1) == 0) {
93d352
+		if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY))
93d352
+			__db_msg(env, "Recreating idle environment");
93d352
+		F_SET(infop, REGION_CREATE_OK);
93d352
+
93d352
+		/*
93d352
+		 * Detach from the environment region; we need to unmap it (and
93d352
+		 * close any file handle) so that we don't leak memory or files.
93d352
+		 */
93d352
+		DB_ASSERT(env, infop->rp == NULL);
93d352
+		infop->rp = &tregion;
93d352
+		(void)__env_sys_detach(env, infop, 0);
93d352
+		goto creation;
93d352
+	}
93d352
+
93d352
+    /* We have an old environment but cannot rebuild it safely. */
93d352
+    if (ret == DB_OLD_VERSION) {
93d352
+ 		__db_errx(env, DB_STR("1539",
93d352
+		    "Build signature doesn't match environment"));
93d352
+		ret = DB_VERSION_MISMATCH;
93d352
+        goto err;
93d352
+    }
93d352
 
93d352
-	/*
93d352
-	 * Make sure the region matches our build.  Special case a region
93d352
-	 * that's all nul bytes, just treat it like any other corruption.
93d352
-	 */
93d352
 	if (renv->majver != DB_VERSION_MAJOR ||
93d352
 	    renv->minver != DB_VERSION_MINOR) {
93d352
-		if (renv->majver != 0 || renv->minver != 0) {
93d352
+		/*
93d352
+		 * Special case a region that's all nul bytes, just treat it
93d352
+		 * like any other corruption.
93d352
+		 */
93d352
+		if (renv->majver == 0 && renv->minver == 0)
93d352
+			ret = EINVAL;
93d352
+		else {
93d352
 			__db_errx(env, DB_STR_A("1538",
93d352
-	    "Program version %d.%d doesn't match environment version %d.%d",
93d352
+	"Program version %d.%d doesn't match in-use environment version %d.%d",
93d352
 			    "%d %d %d %d"), DB_VERSION_MAJOR, DB_VERSION_MINOR,
93d352
 			    renv->majver, renv->minver);
93d352
 			ret = DB_VERSION_MISMATCH;
93d352
-		} else
93d352
-			ret = EINVAL;
93d352
+		}
93d352
 		goto err;
93d352
 	}
93d352
 	if (renv->signature != signature) {
93d352
@@ -289,6 +357,18 @@ user_map_functions:
93d352
 	}
93d352
 	if (renv->magic != DB_REGION_MAGIC)
93d352
 		goto retry;
93d352
+	    /*
93d352
+	     * A bad magic number means that the env is new and not yet available:
93d352
+	     * wait a while and try again.  If the magic number says recovery is in
93d352
+	     * process, remember the env creation time to record that recovery was
93d352
+	     * the reason that the open failed.
93d352
+	     */
93d352
+	    if (renv->magic != DB_REGION_MAGIC) {
93d352
+		    __db_msg(env, "attach sees bad region magic 0x%lx",
93d352
+			(u_long)renv->magic);
93d352
+		    goto retry;
93d352
+	    }
93d352
+
93d352
 
93d352
 	/*
93d352
 	 * Get a reference to the underlying REGION information for this
93d352
@@ -346,6 +426,12 @@ user_map_functions:
93d352
 	return (0);
93d352
 
93d352
 creation:
93d352
+	/* Should this wait for the lock (passing 0 instead of 1)? */
93d352
+	if ((ret = ENV_PRIMARY_LOCK(env, DB_LOCK_WRITE, 1)) != 0) {
93d352
+		__db_err(env, ret, "__env_attach: creation could not lock %s",
93d352
+		    env->lockfhp->name);
93d352
+		goto err;
93d352
+	}
93d352
 	/* Create the environment region. */
93d352
 	F_SET(infop, REGION_CREATE);
93d352
 
93d352
@@ -437,7 +523,14 @@ creation:
93d352
 	renv->minver = (u_int32_t)minver;
93d352
 	renv->patchver = (u_int32_t)patchver;
93d352
 	renv->signature = signature;
93d352
-
93d352
+#ifdef HAVE_PTHREADS_TIMESTAMP
93d352
+	renv->pthreads_timestamp = __os_pthreads_timestamp(env);
93d352
+	{
93d352
+		char *s = getenv("TS_ADJUST");
93d352
+		if (s != NULL)
93d352
+			renv->pthreads_timestamp -= atoi(s);
93d352
+	}
93d352
+#endif
93d352
 	(void)time(&renv->timestamp);
93d352
 	__os_unique_id(env, &renv->envid);
93d352
 
93d352
@@ -513,16 +606,24 @@ find_err:	__db_errx(env, DB_STR_A("1544"
93d352
 		}
93d352
 	}
93d352
 
93d352
-#ifndef HAVE_MUTEX_FCNTL
93d352
-	/*
93d352
-	 * If we're not doing fcntl locking, we can close the file handle.  We
93d352
-	 * no longer need it and the less contact between the buffer cache and
93d352
-	 * the VM, the better.
93d352
-	 */
93d352
+#ifdef HAVE_FCNTL
93d352
+	if ((ret = ENV_PRIMARY_UNLOCK(env)) != 0) {
93d352
+		__db_err(env, ret, "__env_attach: release exclusive lock");
93d352
+		goto err;
93d352
+	}
93d352
+	if ((ret = ENV_PRIMARY_LOCK(env, DB_LOCK_READ, 0)) != 0) {
93d352
+		__db_err(env, ret, "__env_attach: new: acquire shared lock");
93d352
+		goto err;
93d352
+	}
93d352
+#else
93d352
+ 	/*
93d352
+	 * We no longer need the primary region file's handle and the less
93d352
+	 * contact between the buffer cache and the VM, the better.
93d352
+ 	 */
93d352
 	if (env->lockfhp != NULL) {
93d352
 		 (void)__os_closehandle(env, env->lockfhp);
93d352
 		 env->lockfhp = NULL;
93d352
-	}
93d352
+ 	}
93d352
 #endif
93d352
 
93d352
 	/* Everything looks good, we're done. */
93d352
@@ -562,9 +663,9 @@ retry:	/* Close any open file handle. */
93d352
 	/* If we had a temporary error, wait awhile and try again. */
93d352
 	if (ret == 0) {
93d352
 		if (!retry_ok || ++retry_cnt > 3) {
93d352
+			ret = EAGAIN;
93d352
 			__db_errx(env, DB_STR("1546",
93d352
 			    "unable to join the environment"));
93d352
-			ret = EAGAIN;
93d352
 		} else {
93d352
 			__os_yield(env, retry_cnt * 3, 0);
93d352
 			goto loop;
93d352
@@ -575,6 +676,59 @@ retry:	/* Close any open file handle. */
93d352
 }
93d352
 
93d352
 /*
93d352
+ * __env_check_recreate --
93d352
+ *	Determine whether an existing on-disk environment should be recreated
93d352
+ *	because it is not compatible with this compiled BDB library.
93d352
+ *
93d352
+ *	Returns:
93d352
+ *	    0 -
93d352
+ *		The env was generated by this library. No recreation needed.
93d352
+ *	    DB_OLD_VERSION -
93d352
+ *		It was created by an earlier BDB version, or by an earlier
93d352
+ *		version of libpthreads (on certain Linux systems).  The caller
93d352
+ *		will try to recreate it with the currently configured settings.
93d352
+ *	    DB_VERSION_MISMATCH -
93d352
+ *		It was created by a newer version of BDB.  Do not attempt to
93d352
+ *		fix it, something is probably wrong with the application setup.
93d352
+ */
93d352
+static int
93d352
+__env_check_recreate(env, renv, signature)
93d352
+	ENV	*env;
93d352
+	REGENV	*renv;
93d352
+	u_int32_t signature;
93d352
+{
93d352
+#ifdef HAVE_PTHREADS_TIMESTAMP
93d352
+	time_t pthreads_time;
93d352
+	char envtime[CTIME_BUFLEN], libtime[CTIME_BUFLEN];
93d352
+#endif
93d352
+
93d352
+	/* First, bail out if the env is too new for this code to handle. */
93d352
+	if (renv->majver > DB_VERSION_MAJOR ||
93d352
+	    (renv->majver == DB_VERSION_MAJOR &&
93d352
+	    renv->minver > DB_VERSION_MINOR))
93d352
+	    	return (DB_VERSION_MISMATCH);
93d352
+
93d352
+#ifdef HAVE_PTHREADS_TIMESTAMP
93d352
+	pthreads_time = __os_pthreads_timestamp(env);
93d352
+	if (pthreads_time != renv->pthreads_timestamp) {
93d352
+		if (FLD_ISSET(env->dbenv->verbose, DB_VERB_RECOVERY))
93d352
+			__db_msg(env,
93d352
+			"Pthreads timestamp changed: env %.24s current %.24s",
93d352
+			    __os_ctime(&renv->pthreads_timestamp, envtime),
93d352
+			    __os_ctime(&pthreads_time, libtime));
93d352
+		return (DB_OLD_VERSION);
93d352
+	}
93d352
+#endif
93d352
+	if (renv->signature != signature || renv->majver != DB_VERSION_MAJOR ||
93d352
+	    renv->minver != DB_VERSION_MINOR) {
93d352
+		if (FLD_ISSET(env->dbenv->verbose, DB_VERB_RECOVERY))
93d352
+			__db_msg(env, "Signature or version changed");
93d352
+		return (DB_OLD_VERSION);
93d352
+	}
93d352
+    	return (0);
93d352
+}
93d352
+
93d352
+/*
93d352
  * __env_turn_on --
93d352
  *	Turn on the created environment.
93d352
  *
93d352
diff -up db-5.3.28/src/env/env_register.c.pthreads db-5.3.28/src/env/env_register.c
93d352
--- db-5.3.28/src/env/env_register.c.pthreads	2013-09-09 17:35:08.000000000 +0200
93d352
+++ db-5.3.28/src/env/env_register.c	2017-06-13 11:15:15.325215121 +0200
93d352
@@ -19,9 +19,9 @@
93d352
 #define	PID_LEN		(25)				/* PID entry length */
93d352
 
93d352
 #define	REGISTRY_LOCK(env, pos, nowait)					\
93d352
-	__os_fdlock(env, (env)->dbenv->registry, (off_t)(pos), 1, nowait)
93d352
+	__os_fdlock(env, (env)->dbenv->registry, (off_t)(pos), DB_LOCK_WRITE, nowait)
93d352
 #define	REGISTRY_UNLOCK(env, pos)					\
93d352
-	__os_fdlock(env, (env)->dbenv->registry, (off_t)(pos), 0, 0)
93d352
+	__os_fdlock(env, (env)->dbenv->registry, (off_t)(pos), DB_LOCK_NG, 0)
93d352
 #define	REGISTRY_EXCL_LOCK(env, nowait)					\
93d352
 	REGISTRY_LOCK(env, 1, nowait)
93d352
 #define	REGISTRY_EXCL_UNLOCK(env)					\
93d352
diff -up db-5.3.28/src/env/env_stat.c.pthreads db-5.3.28/src/env/env_stat.c
93d352
--- db-5.3.28/src/env/env_stat.c.pthreads	2013-09-09 17:35:08.000000000 +0200
93d352
+++ db-5.3.28/src/env/env_stat.c	2017-06-13 11:15:15.325215121 +0200
93d352
@@ -177,6 +177,10 @@ __env_print_stats(env, flags)
93d352
 	STAT_LONG("Txn version", DB_TXNVERSION);
93d352
 	__db_msg(env,
93d352
 	    "%.24s\tCreation time", __os_ctime(&renv->timestamp, time_buf));
93d352
+#if defined(HAVE_PTHREADS_TIMESTAMP) && defined(HAVE_MUTEX_PTHREADS)
93d352
+	__db_msg(env,
93d352
+	    "%.24s\tlibpthread timestamp", __os_ctime(&renv->pthreads_timestamp, time_buf));
93d352
+#endif
93d352
 	STAT_HEX("Environment ID", renv->envid);
93d352
 	__mutex_print_debug_single(env,
93d352
 	    "Primary region allocation and reference count mutex",
93d352
diff -up db-5.3.28/src/os/os_addrinfo.c.pthreads db-5.3.28/src/os/os_addrinfo.c
93d352
--- db-5.3.28/src/os/os_addrinfo.c.pthreads	2013-09-09 17:35:09.000000000 +0200
93d352
+++ db-5.3.28/src/os/os_addrinfo.c	2017-06-13 11:15:15.325215121 +0200
93d352
@@ -10,6 +10,10 @@
93d352
 
93d352
 #include "db_int.h"
93d352
 
93d352
+#ifdef HAVE_PTHREADS_TIMESTAMP
93d352
+#include <link.h>
93d352
+#endif
93d352
+
93d352
 /*
93d352
  * __os_getaddrinfo and __os_freeaddrinfo wrap the getaddrinfo and freeaddrinfo
93d352
  * calls, as well as the associated platform dependent error handling, mapping
93d352
@@ -177,3 +181,48 @@ __os_freeaddrinfo(env, ai)
93d352
 	}
93d352
 #endif
93d352
 }
93d352
+
93d352
+#ifdef HAVE_PTHREADS_TIMESTAMP
93d352
+/*
93d352
+ *  callback_find_pthreads --
93d352
+ *  	dl_iterate_phdr() calls this once for each loaded library.
93d352
+ *
93d352
+ * Returns:
93d352
+ *	0 - the library does not appear to be libpthreads.
93d352
+ *	1 - the library *does* seem to be libpthreads. Its modification time is
93d352
+ *	    stored into into the last argument's location.
93d352
+ */
93d352
+static int
93d352
+callback_find_pthreads(struct dl_phdr_info *info, size_t size, void *data)
93d352
+{
93d352
+	struct stat stbuf;
93d352
+
93d352
+	/* Stop (return non-zero) when libc is found. */
93d352
+	if (strstr(info->dlpi_name, "libpthread") != NULL &&
93d352
+	    stat(info->dlpi_name, &stbuf) == 0) {
93d352
+		*(time_t *)data = stbuf.st_mtime;
93d352
+		return (1);
93d352
+	}
93d352
+	COMPQUIET(size, 0);
93d352
+	COMPQUIET(data, NULL);
93d352
+	return (0);
93d352
+}
93d352
+
93d352
+/*
93d352
+ * __os_pthreads_timestamp --
93d352
+ *
93d352
+ * PUBLIC: time_t __os_pthreads_timestamp __P((ENV *));
93d352
+ */
93d352
+time_t
93d352
+__os_pthreads_timestamp(env)
93d352
+	ENV *env;
93d352
+{
93d352
+	time_t	timestamp;
93d352
+
93d352
+	timestamp = 0;
93d352
+	dl_iterate_phdr(callback_find_pthreads, &timestamp);
93d352
+
93d352
+	COMPQUIET(env, 0);
93d352
+	return (timestamp);
93d352
+}
93d352
+#endif
93d352
diff -up db-5.3.28/src/os/os_flock.c.pthreads db-5.3.28/src/os/os_flock.c
93d352
--- db-5.3.28/src/os/os_flock.c.pthreads	2013-09-09 17:35:09.000000000 +0200
93d352
+++ db-5.3.28/src/os/os_flock.c	2017-06-13 11:15:15.325215121 +0200
93d352
@@ -10,41 +10,98 @@
93d352
 
93d352
 #include "db_int.h"
93d352
 
93d352
+#if !defined(HAVE_FCNTL) || !defined(HAVE_FLOCK)
93d352
+static int __os_filelocking_notsup __P((ENV *));
93d352
+#endif
93d352
+
93d352
 /*
93d352
  * __os_fdlock --
93d352
  *	Acquire/release a lock on a byte in a file.
93d352
  *
93d352
- * PUBLIC: int __os_fdlock __P((ENV *, DB_FH *, off_t, int, int));
93d352
+ *	The lock modes supported here are:
93d352
+ *	DB_LOCK_NG	- release the lock
93d352
+ *	DB_LOCK_READ	- get shared access
93d352
+ *	DB_LOCK_WRITE	- get exclusive access
93d352
+ *
93d352
+ *	Use fcntl()-like semantics most of the time (DB_REGISTER support). Fcntl
93d352
+ *	supports range locking, but has the additional broken semantics that
93d352
+ *	closing any of the file's descriptors releases any locks, even if its
93d352
+ *	other file descriptors remain open. Thanks SYSV & POSIX.
93d352
+ *	However, if the offset is negative (which is allowed, because POSIX
93d352
+ *	off_t a signed integer) then use flock() instead.  It has only whole-
93d352
+ *	file locks, but they persist until explicitly unlocked or the process
93d352
+ *	exits.
93d352
+ * PUBLIC: int __os_fdlock __P((ENV *, DB_FH *, off_t, db_lockmode_t, int));
93d352
  */
93d352
 int
93d352
-__os_fdlock(env, fhp, offset, acquire, nowait)
93d352
+__os_fdlock(env, fhp, offset, lockmode, nowait)
93d352
 	ENV *env;
93d352
 	DB_FH *fhp;
93d352
-	int acquire, nowait;
93d352
 	off_t offset;
93d352
+	db_lockmode_t lockmode;
93d352
+	int nowait;
93d352
 {
93d352
 #ifdef HAVE_FCNTL
93d352
 	DB_ENV *dbenv;
93d352
 	struct flock fl;
93d352
 	int ret, t_ret;
93d352
+	static char *mode_string[DB_LOCK_WRITE + 1] = {
93d352
+		"unlock",
93d352
+		"read",
93d352
+		"write"
93d352
+	};
93d352
+	short mode_fcntl[DB_LOCK_WRITE + 1] = {
93d352
+		F_UNLCK,
93d352
+		F_RDLCK,
93d352
+		F_WRLCK
93d352
+	};
93d352
+#ifdef HAVE_FLOCK
93d352
+	short mode_flock[DB_LOCK_WRITE + 1] = {
93d352
+		LOCK_UN,
93d352
+		LOCK_SH,
93d352
+		LOCK_EX
93d352
+	};
93d352
+#endif
93d352
 
93d352
 	dbenv = env == NULL ? NULL : env->dbenv;
93d352
 
93d352
 	DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
93d352
+	DB_ASSERT(env, lockmode <= DB_LOCK_WRITE);
93d352
 
93d352
-	if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
93d352
-		__db_msg(env, DB_STR_A("0138",
93d352
-		    "fileops: flock %s %s offset %lu", "%s %s %lu"), fhp->name,
93d352
-		    acquire ? DB_STR_P("acquire"): DB_STR_P("release"),
93d352
-		    (u_long)offset);
93d352
-
93d352
-	fl.l_start = offset;
93d352
-	fl.l_len = 1;
93d352
-	fl.l_type = acquire ? F_WRLCK : F_UNLCK;
93d352
-	fl.l_whence = SEEK_SET;
93d352
-
93d352
-	RETRY_CHK_EINTR_ONLY(
93d352
-	    (fcntl(fhp->fd, nowait ? F_SETLK : F_SETLKW, &fl)), ret);
93d352
+	if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL)) {
93d352
+		if (offset < 0)
93d352
+		      __db_msg(env, DB_STR_A("####",
93d352
+			  "fileops: flock %s %s %s", "%s %s %s"),
93d352
+			  fhp->name, mode_string[lockmode],
93d352
+			  nowait ? "nowait" : "");
93d352
+	      else
93d352
+		      __db_msg(env, DB_STR_A("0020",
93d352
+			  "fileops: fcntls %s %s offset %lu", "%s %s %lu"),
93d352
+			  fhp->name, mode_string[lockmode], (u_long)offset);
93d352
+	}
93d352
+
93d352
+	if (offset < 0) {
93d352
+#ifdef HAVE_FLOCK
93d352
+	        RETRY_CHK_EINTR_ONLY(flock(fhp->fd,
93d352
+	            mode_flock[lockmode] | (nowait ? LOCK_NB : 0)), ret);
93d352
+#else
93d352
+		ret = __os_filelocking_notsup(env);
93d352
+#endif
93d352
+	} else {
93d352
+	        fl.l_start = offset;
93d352
+	        fl.l_len = 1;
93d352
+	        fl.l_whence = SEEK_SET;
93d352
+	        fl.l_type = mode_fcntl[lockmode];
93d352
+	           RETRY_CHK_EINTR_ONLY(
93d352
+	            fcntl(fhp->fd, nowait ? F_SETLK : F_SETLKW, &fl), ret);
93d352
+	}
93d352
+
93d352
+	if (offset < 0 && dbenv != NULL &&
93d352
+	    FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
93d352
+		__db_msg(env, DB_STR_A("####",
93d352
+		    "fileops: flock %s %s %s returns %s", "%s %s %s"),
93d352
+		    fhp->name, mode_string[lockmode],
93d352
+		    nowait ? "nowait" : "", db_strerror(ret));
93d352
 
93d352
 	if (ret == 0)
93d352
 		return (0);
93d352
@@ -53,12 +110,29 @@ __os_fdlock(env, fhp, offset, acquire, n
93d352
 		__db_syserr(env, ret, DB_STR("0139", "fcntl"));
93d352
 	return (t_ret);
93d352
 #else
93d352
+	ret = __os_filelocking_notsup(env);
93d352
 	COMPQUIET(fhp, NULL);
93d352
-	COMPQUIET(acquire, 0);
93d352
+	COMPQUIET(lockmode, 0);
93d352
 	COMPQUIET(nowait, 0);
93d352
 	COMPQUIET(offset, 0);
93d352
+	return (ret)
93d352
+#endif
93d352
+}
93d352
+
93d352
+
93d352
+#if !defined(HAVE_FCNTL) || !defined(HAVE_FLOCK)
93d352
+/*
93d352
+ * __os_filelocking_notsup --
93d352
+ *	Generate an error message if fcntl() or flock() is requested on a
93d352
+ *	platform that does not support it.
93d352
+ *
93d352
+ */
93d352
+static int
93d352
+__os_filelocking_notsup(env)
93d352
+ 	ENV *env;
93d352
+{
93d352
 	__db_syserr(env, DB_OPNOTSUP, DB_STR("0140",
93d352
 	    "advisory file locking unavailable"));
93d352
 	return (DB_OPNOTSUP);
93d352
-#endif
93d352
 }
93d352
+#endif
93d352
diff -up db-5.3.28/src/os/os_map.c.pthreads db-5.3.28/src/os/os_map.c
93d352
--- db-5.3.28/src/os/os_map.c.pthreads	2013-09-09 17:35:09.000000000 +0200
93d352
+++ db-5.3.28/src/os/os_map.c	2017-06-13 11:15:15.325215121 +0200
93d352
@@ -32,7 +32,7 @@ static int __no_system_mem __P((ENV *));
93d352
 
93d352
 /*
93d352
  * __os_attach --
93d352
- *	Create/join a shared memory region.
93d352
+ *	Create/join a 'shared' region of Berkeley DB memory.
93d352
  *
93d352
  * PUBLIC: int __os_attach __P((ENV *, REGINFO *, REGION *));
93d352
  */
93d352
@@ -50,6 +50,7 @@ __os_attach(env, infop, rp)
93d352
 	 * so there must be a valid handle.
93d352
 	 */
93d352
 	DB_ASSERT(env, env != NULL && env->dbenv != NULL);
93d352
+	DB_ASSERT(env, infop->fhp == NULL);
93d352
 	dbenv = env->dbenv;
93d352
 
93d352
 	if (DB_GLOBAL(j_region_map) != NULL) {