From 88381e53fc9a689b88bb8a60b687653b5c7f820b Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 13 Aug 2023 12:40:27 +0000 Subject: [PATCH] Add a mutex for auto-extensions, tied in to the open() process since that's the route into auto-extensions. FossilOrigin-Name: 8da97e0db4eeacf91aa6fd909fd7cb73b050d194dfc7739a502b55f7eca6d7b1 --- ext/jni/src/c/sqlite3-jni.c | 197 ++++++++++++--------- ext/jni/src/org/sqlite/jni/SQLite3Jni.java | 42 +++-- manifest | 14 +- manifest.uuid | 2 +- 4 files changed, 140 insertions(+), 115 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index eebe124f89..149feef554 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -400,8 +400,6 @@ static void S3JniNphCache_clear(JNIEnv * const env, S3JniNphCache * const p){ memset(p, 0, sizeof(S3JniNphCache)); } -#define S3JNI_ENABLE_AUTOEXT 1 -#if S3JNI_ENABLE_AUTOEXT /* Whether auto extensions are feasible here is currently unknown due to... @@ -430,7 +428,6 @@ struct S3JniAutoExtension { S3JniAutoExtension *pNext /* next linked-list entry */; S3JniAutoExtension *pPrev /* previous linked-list entry */; }; -#endif /** State for various hook callbacks. */ typedef struct S3JniHook S3JniHook; @@ -518,6 +515,7 @@ static struct { unsigned envCacheMisses; unsigned nMutexEnv /* number of times envCache.mutex was entered */; unsigned nMutexPerDb /* number of times perDb.mutex was entered */; + unsigned nMutexAutoExt /* number of times autoExt.mutex was entered */; unsigned nDestroy /* xDestroy() calls across all types */; struct { /* Number of calls for each type of UDF callback. */ @@ -528,10 +526,9 @@ static struct { unsigned nInverse; } udf; } metrics; -#if S3JNI_ENABLE_AUTOEXT struct { S3JniAutoExtension *pHead /* Head of the auto-extension list */; - S3JniDb * psOpening /* FIXME: move into envCache. Handle to the + S3JniDb * pdbOpening /* FIXME: move into envCache. Handle to the being-opened db. We need this so that auto extensions can have a consistent view of the cross-language db connection and @@ -542,36 +539,50 @@ static struct { manipulation of the auto-extension list while extensions are running. */; + sqlite3_mutex * mutex /* mutex for aUsed and aFree */; + void const * locker /* Mutex is locked on this object's behalf */; } autoExt; -#endif } S3JniGlobal; #define MUTEX_ASSERT_LOCKER_ENV \ assert( (env) == S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) #define MUTEX_ASSERT_NOTLOCKER_ENV \ assert( (env) != S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) -#define MUTEX_ENTER_ENV \ +#define MUTEX_ENTER_ENV \ /*MARKER(("Entering ENV mutex@%p %s.\n", env, __func__));*/ \ - MUTEX_ASSERT_NOTLOCKER_ENV; \ - sqlite3_mutex_enter( S3JniGlobal.envCache.mutex ); \ - ++S3JniGlobal.metrics.nMutexEnv; \ + MUTEX_ASSERT_NOTLOCKER_ENV; \ + sqlite3_mutex_enter( S3JniGlobal.envCache.mutex ); \ + ++S3JniGlobal.metrics.nMutexEnv; \ S3JniGlobal.envCache.locker = env -#define MUTEX_LEAVE_ENV \ +#define MUTEX_LEAVE_ENV \ /*MARKER(("Leaving ENV mutex @%p %s.\n", env, __func__));*/ \ - MUTEX_ASSERT_LOCKER_ENV; \ - S3JniGlobal.envCache.locker = 0; \ + MUTEX_ASSERT_LOCKER_ENV; \ + S3JniGlobal.envCache.locker = 0; \ sqlite3_mutex_leave( S3JniGlobal.envCache.mutex ) -#define MUTEX_ASSERT_LOCKED_PDB \ +#define MUTEX_ASSERT_LOCKED_PDB \ assert( 0 != S3JniGlobal.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ) -#define MUTEX_ENTER_PDB \ +#define MUTEX_ENTER_PDB \ /*MARKER(("Entering PerDb mutex@%p %s.\n", env, __func__));*/ \ - sqlite3_mutex_enter( S3JniGlobal.perDb.mutex ); \ - ++S3JniGlobal.metrics.nMutexPerDb; \ + sqlite3_mutex_enter( S3JniGlobal.perDb.mutex ); \ + ++S3JniGlobal.metrics.nMutexPerDb; \ S3JniGlobal.perDb.locker = env; -#define MUTEX_LEAVE_PDB \ +#define MUTEX_LEAVE_PDB \ /*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \ - S3JniGlobal.perDb.locker = 0; \ + S3JniGlobal.perDb.locker = 0; \ sqlite3_mutex_leave( S3JniGlobal.perDb.mutex ) +#define MUTEX_ENTER_EXT \ + /*MARKER(("Entering autoExt mutex@%p %s.\n", env, __func__));*/ \ + sqlite3_mutex_enter( S3JniGlobal.autoExt.mutex ); \ + ++S3JniGlobal.metrics.nMutexAutoExt +#define MUTEX_TRY_EXT(FAIL_EXPR) \ + /*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \ + if( sqlite3_mutex_try( S3JniGlobal.autoExt.mutex ) ){ FAIL_EXPR; } \ + S3JniGlobal.autoExt.locker = env; \ + ++S3JniGlobal.metrics.nMutexAutoExt +#define MUTEX_LEAVE_EXT \ + /*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \ + S3JniGlobal.autoExt.locker = 0; \ + sqlite3_mutex_leave( S3JniGlobal.autoExt.mutex ) #define OOM_CHECK(VAR) if(!(VAR)) s3jni_oom(env) static void s3jni_oom(JNIEnv * const env){ @@ -1023,7 +1034,6 @@ static int S3JniGlobal_env_uncache(JNIEnv * const env){ This simple cache catches >99% of searches in the current (2023-07-31) tests. */ -FIXME_THREADING(S3JniEnvCache) static S3JniNphCache * S3JniGlobal_nph_cache(JNIEnv * const env, const char *zClassName){ /** According to: @@ -1041,8 +1051,8 @@ static S3JniNphCache * S3JniGlobal_nph_cache(JNIEnv * const env, const char *zCl cached as well. Reminder: we do not need a mutex for the envRow->nph cache - because all nph entries are per-thread and envCache.mutex - already guards the fetching of envRow. + because all nph entries are per-thread and envCache.mutex already + guards the fetching of envRow. */ struct S3JniEnvCache * const envRow = S3JniGlobal_env_cache(env); S3JniNphCache * freeSlot = 0; @@ -1221,8 +1231,6 @@ static void S3JniDb_dump(S3JniDb *s){ Returns NULL if jDb and pDb are both NULL or if there is no matching S3JniDb entry for pDb or the pointer fished out of jDb. */ -FIXME_THREADING(S3JniEnvCache) -FIXME_THREADING(perDb) static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){ S3JniDb * s = 0; if(jDb || pDb){ @@ -1242,7 +1250,6 @@ static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){ return s; } -#if S3JNI_ENABLE_AUTOEXT /** Unlink ax from S3JniGlobal.autoExt and free it. */ @@ -1279,7 +1286,7 @@ static S3JniAutoExtension * S3JniAutoExtension_alloc(JNIEnv *const env, return 0; } ax->midFunc = (*env)->GetMethodID(env, klazz, "xEntryPoint", - "(Lorg/sqlite/jni/sqlite3;)I"); + "(Lorg/sqlite/jni/sqlite3;)I"); if(!ax->midFunc){ MARKER(("Error getting xEntryPoint(sqlite3) from object.")); S3JniAutoExtension_free(env, ax); @@ -1292,7 +1299,6 @@ static S3JniAutoExtension * S3JniAutoExtension_alloc(JNIEnv *const env, } return ax; } -#endif /* S3JNI_ENABLE_AUTOEXT */ /** Requires that jCx be a Java-side sqlite3_context wrapper for pCx. @@ -1881,35 +1887,37 @@ WRAP_INT_SVALUE(1value_1numeric_1type, sqlite3_value_numeric_type) WRAP_INT_SVALUE(1value_1subtype, sqlite3_value_subtype) WRAP_INT_SVALUE(1value_1type, sqlite3_value_type) -#if S3JNI_ENABLE_AUTOEXT +static JNIEnv * s3jni_get_env(void){ + JNIEnv * env = 0; + if( (*S3JniGlobal.jvm)->GetEnv(S3JniGlobal.jvm, (void **)&env, + JNI_VERSION_1_8) ){ + fprintf(stderr, "Fatal error: cannot get current JNIEnv.\n"); + abort(); + } + return env; +} + /* Central auto-extension handler. */ -FIXME_THREADING(autoExt) -static int s3jni_auto_extension(sqlite3 *pDb, const char **pzErr, - const struct sqlite3_api_routines *ignored){ +static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr, + const struct sqlite3_api_routines *ignored){ S3JniAutoExtension const * pAX = S3JniGlobal.autoExt.pHead; int rc; JNIEnv * env = 0; - S3JniDb * const ps = S3JniGlobal.autoExt.psOpening; - //MARKER(("auto-extension on open()ing ps@%p db@%p\n", ps, pDb)); - S3JniGlobal.autoExt.psOpening = 0; + S3JniDb * const ps = S3JniGlobal.autoExt.pdbOpening; + + assert( S3JniGlobal.autoExt.locker ); + assert( S3JniGlobal.autoExt.locker == ps ); + S3JniGlobal.autoExt.pdbOpening = 0; if( !pAX ){ assert( 0==S3JniGlobal.autoExt.isRunning ); return 0; - } - else if( S3JniGlobal.autoExt.isRunning ){ - /* Necessary to avoid certain endless loop/stack overflow cases. */ - *pzErr = sqlite3_mprintf("Auto-extensions must not be triggered while " - "auto-extensions are running."); - return SQLITE_MISUSE; - } - else if(!ps){ - MARKER(("Internal error: cannot find S3JniDb for auto-extension\n")); - return SQLITE_ERROR; - }else if( (*S3JniGlobal.jvm)->GetEnv(S3JniGlobal.jvm, (void **)&env, JNI_VERSION_1_8) ){ - assert(!"Cannot get JNIEnv"); - *pzErr = sqlite3_mprintf("Could not get current JNIEnv."); + }else if( S3JniGlobal.autoExt.locker != ps ) { + *pzErr = sqlite3_mprintf("Internal error: unexpected path lead to " + "running an auto-extension."); return SQLITE_ERROR; } + env = s3jni_get_env(); + //MARKER(("auto-extension on open()ing ps@%p db@%p\n", ps, pDb)); assert( !ps->pDb /* it's still being opened */ ); ps->pDb = pDb; assert( ps->jDb ); @@ -1941,8 +1949,9 @@ JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){ S3JniAutoExtension * ax; if( !jAutoExt ) return SQLITE_MISUSE; - else if( 0==once && ++once ){ - sqlite3_auto_extension( (void(*)(void))s3jni_auto_extension ); + MUTEX_ENTER_EXT; + if( 0==once && ++once ){ + sqlite3_auto_extension( (void(*)(void))s3jni_run_java_auto_extensions ); } ax = S3JniGlobal.autoExt.pHead; for( ; ax; ax = ax->pNext ){ @@ -1950,9 +1959,10 @@ JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){ return 0 /* C API treats this as a no-op. */; } } - return S3JniAutoExtension_alloc(env, jAutoExt) ? 0 : SQLITE_NOMEM; + ax = S3JniAutoExtension_alloc(env, jAutoExt); + MUTEX_LEAVE_EXT; + return ax ? 0 : SQLITE_NOMEM; } -#endif /* S3JNI_ENABLE_AUTOEXT */ FIXME_THREADING(S3JniEnvCache) JDECL(jint,1bind_1blob)(JENV_CSELF, jobject jpStmt, @@ -2088,20 +2098,23 @@ JDECL(jint,1busy_1timeout)(JENV_CSELF, jobject jDb, jint ms){ return SQLITE_MISUSE; } -#if S3JNI_ENABLE_AUTOEXT FIXME_THREADING(autoExt) JDECL(jboolean,1cancel_1auto_1extension)(JENV_CSELF, jobject jAutoExt){ - S3JniAutoExtension * ax;; - if( S3JniGlobal.autoExt.isRunning ) return JNI_FALSE; - for( ax = S3JniGlobal.autoExt.pHead; ax; ax = ax->pNext ){ - if( (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){ - S3JniAutoExtension_free(env, ax); - return JNI_TRUE; + S3JniAutoExtension * ax; + jboolean rc = JNI_FALSE; + MUTEX_ENTER_EXT; + if( !S3JniGlobal.autoExt.isRunning ) { + for( ax = S3JniGlobal.autoExt.pHead; ax; ax = ax->pNext ){ + if( (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){ + S3JniAutoExtension_free(env, ax); + rc = JNI_TRUE; + break; + } } } - return JNI_FALSE; + MUTEX_LEAVE_EXT; + return rc; } -#endif /* S3JNI_ENABLE_AUTOEXT */ /** @@ -2649,27 +2662,41 @@ JDECL(jlong,1last_1insert_1rowid)(JENV_CSELF, jobject jpDb){ static int s3jni_open_pre(JNIEnv * const env, S3JniEnvCache **jc, jstring jDbName, char **zDbName, S3JniDb ** ps, jobject *jDb){ + int rc = 0; + MUTEX_TRY_EXT(return SQLITE_BUSY); *jc = S3JniGlobal_env_cache(env); - if(!*jc) return SQLITE_NOMEM; + if(!*jc){ + rc = SQLITE_NOMEM; + goto end; + } *zDbName = jDbName ? s3jni_jstring_to_utf8(*jc, jDbName, 0) : 0; - if(jDbName && !*zDbName) return SQLITE_NOMEM; + if(jDbName && !*zDbName){ + rc = SQLITE_NOMEM; + goto end; + } *jDb = new_sqlite3_wrapper(env, 0); if( !*jDb ){ sqlite3_free(*zDbName); *zDbName = 0; - return SQLITE_NOMEM; + rc = SQLITE_NOMEM; + goto end; } MUTEX_ENTER_PDB; *ps = S3JniDb_alloc(env, 0, *jDb); MUTEX_LEAVE_PDB; -#if S3JNI_ENABLE_AUTOEXT if(*ps){ - assert(!S3JniGlobal.autoExt.psOpening); - S3JniGlobal.autoExt.psOpening = *ps; + S3JniGlobal.autoExt.pdbOpening = *ps; + S3JniGlobal.autoExt.locker = *ps; + }else{ + rc = SQLITE_NOMEM; } -#endif //MARKER(("pre-open ps@%p\n", *ps)); - return *ps ? 0 : SQLITE_NOMEM; +end: + /* Remain in autoExt.mutex until s3jni_open_post(). */ + if(rc){ + MUTEX_LEAVE_EXT; + } + return rc; } /** @@ -2686,10 +2713,8 @@ static int s3jni_open_pre(JNIEnv * const env, S3JniEnvCache **jc, static int s3jni_open_post(JNIEnv * const env, S3JniDb * ps, sqlite3 **ppDb, jobject jOut, int theRc){ //MARKER(("post-open() ps@%p db@%p\n", ps, *ppDb)); -#if S3JNI_ENABLE_AUTOEXT - assert( S3JniGlobal.autoExt.pHead ? ps!=S3JniGlobal.autoExt.psOpening : 1 ); - S3JniGlobal.autoExt.psOpening = 0; -#endif + assert( S3JniGlobal.autoExt.locker == ps ); + S3JniGlobal.autoExt.pdbOpening = 0; if(*ppDb){ assert(ps->jDb); ps->pDb = *ppDb; @@ -2701,6 +2726,7 @@ static int s3jni_open_post(JNIEnv * const env, S3JniDb * ps, ps = 0; } OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0); + MUTEX_LEAVE_EXT; return theRc; } @@ -2710,8 +2736,8 @@ JDECL(jint,1open)(JENV_CSELF, jstring strName, jobject jOut){ jobject jDb = 0; S3JniDb * ps = 0; S3JniEnvCache * jc = 0; - S3JniDb * const prevOpening = S3JniGlobal.autoExt.psOpening; - int rc = s3jni_open_pre(env, &jc, strName, &zName, &ps, &jDb); + S3JniDb * const prevOpening = S3JniGlobal.autoExt.pdbOpening; + int rc= s3jni_open_pre(env, &jc, strName, &zName, &ps, &jDb); if( 0==rc ){ rc = sqlite3_open(zName, &pOut); //MARKER(("env=%p, *env=%p\n", env, *env)); @@ -2720,7 +2746,7 @@ JDECL(jint,1open)(JENV_CSELF, jstring strName, jobject jOut){ assert(rc==0 ? pOut!=0 : 1); sqlite3_free(zName); } - S3JniGlobal.autoExt.psOpening = prevOpening; + S3JniGlobal.autoExt.pdbOpening = prevOpening; return (jint)rc; } @@ -2732,7 +2758,7 @@ JDECL(jint,1open_1v2)(JENV_CSELF, jstring strName, S3JniDb * ps = 0; S3JniEnvCache * jc = 0; char *zVfs = 0; - S3JniDb * const prevOpening = S3JniGlobal.autoExt.psOpening; + S3JniDb * const prevOpening = S3JniGlobal.autoExt.pdbOpening; int rc = s3jni_open_pre(env, &jc, strName, &zName, &ps, &jDb); if( 0==rc && strVfs ){ zVfs = s3jni_jstring_to_utf8(jc, strVfs, 0); @@ -2747,10 +2773,10 @@ JDECL(jint,1open_1v2)(JENV_CSELF, jstring strName, /*MARKER(("zName=%s, zVfs=%s, pOut=%p, flags=%d, nrc=%d\n", zName, zVfs, pOut, (int)flags, nrc));*/ rc = s3jni_open_post(env, ps, &pOut, jOut, rc); + S3JniGlobal.autoExt.pdbOpening = prevOpening; assert(rc==0 ? pOut!=0 : 1); sqlite3_free(zName); sqlite3_free(zVfs); - S3JniGlobal.autoExt.psOpening = prevOpening; return (jint)rc; } @@ -2886,15 +2912,13 @@ JDECL(jint,1reset)(JENV_CSELF, jobject jpStmt){ return rc; } -#if S3JNI_ENABLE_AUTOEXT JDECL(void,1reset_1auto_1extension)(JENV_CSELF){ - if(!S3JniGlobal.autoExt.isRunning){ - while( S3JniGlobal.autoExt.pHead ){ - S3JniAutoExtension_free(env, S3JniGlobal.autoExt.pHead); - } + MUTEX_ENTER_EXT; + while( S3JniGlobal.autoExt.pHead ){ + S3JniAutoExtension_free(env, S3JniGlobal.autoExt.pHead); } + MUTEX_LEAVE_EXT; } -#endif /* S3JNI_ENABLE_AUTOEXT */ /* sqlite3_result_text/blob() and friends. */ static void result_blob_text(int asBlob, int as64, @@ -3504,9 +3528,10 @@ JDECL(void,1do_1something_1for_1developer)(JENV_CSELF){ printf("\tJNIEnv cache %u misses, %u hits\n", S3JniGlobal.metrics.envCacheMisses, S3JniGlobal.metrics.envCacheHits); - printf("\tMutex entry: %u env, %u perDb\n", + printf("Mutex entry:\n\t%u env\n\t%u perDb\n\t%u autoExt (mostly via open[_v2]())\n", S3JniGlobal.metrics.nMutexEnv, - S3JniGlobal.metrics.nMutexPerDb); + S3JniGlobal.metrics.nMutexPerDb, + S3JniGlobal.metrics.nMutexAutoExt); puts("Java-side UDF calls:"); #define UDF(T) printf("\t%-8s = %u\n", "x" #T, S3JniGlobal.metrics.udf.n##T) UDF(Func); UDF(Step); UDF(Final); UDF(Value); UDF(Inverse); @@ -4418,6 +4443,8 @@ Java_org_sqlite_jni_SQLite3Jni_init(JENV_CSELF){ OOM_CHECK( S3JniGlobal.envCache.mutex ); S3JniGlobal.perDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); OOM_CHECK( S3JniGlobal.perDb.mutex ); + S3JniGlobal.autoExt.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + OOM_CHECK( S3JniGlobal.autoExt.mutex ); #if 0 /* Just for sanity checking... */ (void)S3JniGlobal_env_cache(env); diff --git a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java index e7aa10ebae..dbd2e4bae7 100644 --- a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java +++ b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java @@ -178,24 +178,25 @@ public final class SQLite3Jni { not have access to the sqlite3_api object which native auto-extensions do. - - If an auto-extension opens a db, thereby triggering recursion - in the auto-extension handler, it will fail with a message - explaining that recursion is not permitted. + - If an auto-extension opens a db, opening will fail with SQLITE_BUSY. + The alternative would be endless recursion into the auto-extension. - - All of the other auto extension routines will fail without side - effects if invoked from within the execution of an - auto-extension. i.e. auto extensions can neither be added, + - The list of auto-extensions must not be manipulated from within + an auto-extension. Auto extensions can neither be added, removed, nor cleared while one registered with this function is - running. Auto-extensions registered directly with the library - via C code, as opposed to indirectly via Java, do not have that - limitation. + running. Attempting to do so may lead to a deadlock. See the AutoExtension class docs for more information. Achtung: it is as yet unknown whether auto extensions registered from one JNIEnv (thread) can be safely called from another. + + Design note: this family of methods is synchronized in order to + help avoid a small race condition where an in-progress + sqlite3_reset_auto_extension() or sqlite3_cancel_auto_extension() + could cause sqlite3_open() to fail with SQLITE_BUSY. */ - public static native int sqlite3_auto_extension(@NotNull AutoExtension callback); + public static synchronized native int sqlite3_auto_extension(@NotNull AutoExtension callback); public static int sqlite3_bind_blob( @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data @@ -296,7 +297,7 @@ public final class SQLite3Jni { effects, if auto extensions are currently running. (The JNI-level list of extensions cannot be manipulated while it is being traversed.) */ - public static native boolean sqlite3_cancel_auto_extension( + public static synchronized native boolean sqlite3_cancel_auto_extension( @NotNull AutoExtension ax ); @@ -313,11 +314,11 @@ public final class SQLite3Jni { ); public static native int sqlite3_close( - @NotNull sqlite3 db + @Nullable sqlite3 db ); public static native int sqlite3_close_v2( - @NotNull sqlite3 db + @Nullable sqlite3 db ); public static native byte[] sqlite3_column_blob( @@ -593,19 +594,16 @@ public final class SQLite3Jni { Recall that even if opening fails, the output pointer might be non-null. Any error message about the failure will be in that object and it is up to the caller to sqlite3_close() that - db handle. + db handle. Passing a null to sqlite3_close() is legal. - Pedantic note: though any number of Java-level sqlite3 objects - may refer to/wrap a single C-level (sqlite3*), the JNI internals - take a reference to the object which is passed to sqlite3_open() - or sqlite3_open_v2() so that they have a predictible object to - pass to, e.g., the sqlite3_collation_needed() callback. + Design note: this method is synchronized in order to help + alleviate a race condition involving auto-extensions. */ - public static native int sqlite3_open( + public static synchronized native int sqlite3_open( @Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb ); - public static native int sqlite3_open_v2( + public static synchronized native int sqlite3_open_v2( @Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb, int flags, @Nullable String zVfs ); @@ -729,7 +727,7 @@ public final class SQLite3Jni { extensions are currently running. (The JNI-level list of extensions cannot be manipulated while it is being traversed.) */ - public static native void sqlite3_reset_auto_extension(); + public static synchronized native void sqlite3_reset_auto_extension(); public static native void sqlite3_result_double( @NotNull sqlite3_context cx, double v diff --git a/manifest b/manifest index 48db0129da..dbbd37eaaa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssome\sdocs\sand\smetrics\sfor\sthe\snew\smutex\sinternals. -D 2023-08-13T10:28:35.456 +C Add\sa\smutex\sfor\sauto-extensions,\stied\sin\sto\sthe\sopen()\sprocess\ssince\sthat's\sthe\sroute\sinto\sauto-extensions. +D 2023-08-13T12:40:27.217 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -234,7 +234,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile a9e11b92e620058558cbc1a2d49f8ec53c78d6a989b9db0b7d0b649b9f174881 F ext/jni/README.md 7a614a2fa6c561205f7a53fd8626cf93a7b5711ff454fc1814517f796df398eb F ext/jni/jar-dist.make f90a553203a57934bf275bed86479485135a52f48ac5c1cfe6499ae07b0b35a4 -F ext/jni/src/c/sqlite3-jni.c 44c1da6d1ae9d8ea2af16dd5c1d17224a655c9c94135892f81571b2481896431 +F ext/jni/src/c/sqlite3-jni.c 4f6f8f2dec309a6b117a6e8f460078b5f6f6b65a17c530ae2f5907b6425d714c F ext/jni/src/c/sqlite3-jni.h f10d2f38720687c70ecdd5e44f6e8db98efee2caa05fc86b2d9e0c76e6cc0a18 F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892 F ext/jni/src/org/sqlite/jni/AutoExtension.java 18e83f6f463e306df60b2dceb65247d32af1f78af4bbbae9155411a8c6cdb093 @@ -254,7 +254,7 @@ F ext/jni/src/org/sqlite/jni/ProgressHandler.java 6f62053a828a572de809828b1ee495 F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7ce7797f2c6c7fca2004ff12ce20f86 F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564 F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46 -F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 7933fabc267dbfdccb784563d8c404f90275fe9418e8cd6c43c584bc9c57f70f +F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 5eeba0b1a00fb34bc93fe60186f6032fcf4d568fc5868d70029883d3d07cc306 F ext/jni/src/org/sqlite/jni/Tester1.java fc2ec1f1be58474112b9df8284f0157b64872107f446154c3d0bf1742b924d2b F ext/jni/src/org/sqlite/jni/TesterFts5.java 59e22dd24af033ea8827d36225a2f3297908fb6af8818ead8850c6c6847557b1 F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d @@ -2091,8 +2091,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c64e6a52ac79164be37fe643a4a39bd187af198a379410def8b8419f7c2224d4 -R cd02d0fb58628c824a2d7de7efc47b02 +P 33d1780b43182d2574adbc1928707af825c485c99762738e58bc6d7c6c52ac6a +R 6a1ce79c2368c04d74cde070b44b6572 U stephan -Z 6ab46f9c79559c9df9412a6d1bef3261 +Z d637a436f204decfbfbf40fa44769c67 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0fe79c981a..4f1f622ee9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -33d1780b43182d2574adbc1928707af825c485c99762738e58bc6d7c6c52ac6a \ No newline at end of file +8da97e0db4eeacf91aa6fd909fd7cb73b050d194dfc7739a502b55f7eca6d7b1 \ No newline at end of file -- 2.47.2