Index: build/ac-macros/sqlite.m4 =================================================================== --- build/ac-macros/sqlite.m4 (revision 27973) +++ build/ac-macros/sqlite.m4 (working copy) @@ -52,6 +52,8 @@ svn_lib_sqlite="yes" SVN_SQLITE_INCLUDES="`$pkg_config $SQLITE_PKGNAME --cflags`" SVN_SQLITE_LIBS="`$pkg_config $SQLITE_PKGNAME --libs`" + AC_CHECK_LIB(sqlite3, sqlite3_threadsafe, + [threadsafety_runtime_check_avail=yes]) ;; *) AC_MSG_RESULT([none or unsupported $sqlite_version]) @@ -68,6 +70,11 @@ fi ]) + if test "$threadsafety_runtime_check_avail" = "yes"; then + AC_DEFINE([SVN_HAVE_SQLITE_THREADSAFE_PREDICATE], [1], + [Defined if SQLite 3.5+'s thread-safety runtime check is available.]) + fi + AC_SUBST(SVN_SQLITE_INCLUDES) AC_SUBST(SVN_SQLITE_LIBS) ]) @@ -94,8 +101,12 @@ else SVN_SQLITE_LIBS="-lsqlite3" fi - ]) ]) + AC_CHECK_LIB(sqlite3, sqlite3_threadsafe, + [threadsafety_runtime_check_avail=yes]) + ]) + ]) + if test "$sqlite_dir" != "" && test -d "$sqlite_dir"; then CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" Index: subversion/libsvn_fs_util/sqlite-util.c =================================================================== --- subversion/libsvn_fs_util/sqlite-util.c (revision 27973) +++ subversion/libsvn_fs_util/sqlite-util.c (working copy) @@ -23,9 +23,11 @@ #include #include +#include #include +#include "svn_types.h" #include "svn_fs.h" #include "svn_path.h" #include "svn_mergeinfo.h" @@ -189,11 +191,66 @@ return svn_fs__sqlite_stmt_error(stmt); } +#ifndef SVN_HAVE_SQLITE_THREADSAFE_PREDICATE +#include +#endif + +/* If possible, verify that SQLite was compiled in a thread-safe + manner. The library will be unloaded when POOL is destroyed. */ +static svn_error_t * +init_sqlite(apr_pool_t *pool) +{ + svn_boolean_t is_threadsafe = TRUE; + + /* SQLite 3.5 allows verification of its thread-safety at runtime. + Older versions are simply expected to have been configured with + --enable-threadsafe, which compiles with -DSQLITE_THREADSAFE=1 + (or -DTHREADSAFE, for older versions). */ +#ifdef SVN_HAVE_SQLITE_THREADSAFE_PREDICATE + /* sqlite3_threadsafe() was available at Subversion 'configure'-time. */ + is_threadsafe = sqlite3_threadsafe(); + +#elsif APR_HAS_DSO + /* Attempt to dynamically load sqlite3_threadsafe(), since the + version of SQLite present at compile-time may've changed. */ + apr_status_t status; + apr_dso_handle_t *dso = NULL; + apr_dso_handle_sym_t symbol; + +#if DARWIN + status = apr_dso_load(&dso, "libsqlite3.dylib", pool); +#endif + if (dso == NULL) + status = apr_dso_load(&dso, "libsqlite3.so", pool); + + if (dso) + { + status = apr_dso_sym(&symbol, dso, "sqlite3_threadsafe"); + if (symbol && !status) + { + int (*threadsafe_func)(void) = symbol; + is_threadsafe = (*threadsafe_func)(); + } + } +#endif /* SVN_HAVE_SQLITE_THREADSAFE_PREDICATE */ + + if (! is_threadsafe) + return svn_error_create(SVN_ERR_FS_SQLITE_ERROR, NULL, + _("SQLite is required to be compiled and run in " + "thread-safe mode")); + return SVN_NO_ERROR; +} + svn_error_t * svn_fs__sqlite_open(sqlite3 **db, const char *repos_path, apr_pool_t *pool) { - const char *db_path = svn_path_join(repos_path, - SVN_FS__SQLITE_DB_NAME, pool); + const char *db_path; + + SVN_ERR(init_sqlite(pool)); + + db_path = svn_path_join(repos_path, SVN_FS__SQLITE_DB_NAME, pool); + + /* Open the database. */ SVN_FS__SQLITE_ERR(sqlite3_open(db_path, db), *db); /* Retry until timeout when database is busy. */ SVN_FS__SQLITE_ERR(sqlite3_busy_timeout(*db, BUSY_TIMEOUT), *db);