diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index a9e1552cf8..1595fcbb3c 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -574,7 +574,10 @@ struct S3JniGlobalType { ** JNIEnv when necessary. */ JavaVM * jvm; - /* Global mutex. */ + /* + ** Global mutex. It must not be used for anything which might call + ** back into the JNI layer. + */ sqlite3_mutex * mutex; /* ** Cache of references to Java classes and method IDs for @@ -647,19 +650,22 @@ struct S3JniGlobalType { #ifdef SQLITE_ENABLE_FTS5 struct { volatile jobject jExt /* Global ref to Java singleton for the - Fts5ExtensionApi instance. */; + Fts5ExtensionApi instance. */; struct { - jfieldID fidA /* Fts5Phrase::a member */; - jfieldID fidB /* Fts5Phrase::b member */; + jfieldID fidA /* Fts5Phrase::a member */; + jfieldID fidB /* Fts5Phrase::b member */; } jPhraseIter; } fts5; #endif #ifdef SQLITE_ENABLE_SQLLOG struct { - S3JniHook sqllog /* sqlite3_config(SQLITE_CONFIG_SQLLOG) callback */; - S3JniHook * aFree /* free-item list, for recycling. Guarded by - the global mutex. */; - } hooks; + S3JniHook sqllog /* sqlite3_config(SQLITE_CONFIG_SQLLOG) callback */; + S3JniHook * aFree /* free-item list, for recycling. */; + sqlite3_mutex * mutex /* mutex for aFree */; + volatile const void * locker /* object on whose behalf the mutex + is held. Only for sanity checking + in debug builds. */; + } hook; #endif #ifdef SQLITE_JNI_ENABLE_METRICS /* Internal metrics. */ @@ -669,7 +675,8 @@ struct S3JniGlobalType { volatile unsigned nEnvAlloc; volatile unsigned nMutexEnv /* number of times envCache.mutex was entered for a S3JniEnv operation. */; - volatile unsigned nMutexNph /* number of times SJG.mutex was entered for NPH init */; + volatile unsigned nMutexNph /* number of times SJG.mutex was entered */; + volatile unsigned nMutexHook /* number of times SJG.mutex hooks.was entered */; volatile unsigned nMutexPerDb /* number of times perDb.mutex was entered */; volatile unsigned nMutexAutoExt /* number of times autoExt.mutex was entered */; volatile unsigned nMutexGlobal /* number of times global mutex was entered. */; @@ -717,6 +724,21 @@ static void s3jni_incr( volatile unsigned int * const p ){ /* Helpers for working with specific mutexes. */ #if SQLITE_THREADSAFE +#define s3jni_mutex_enter2(M, Metric) \ + sqlite3_mutex_enter( M ); \ + s3jni_incr( &SJG.metrics.Metric ) +#define s3jni_mutex_leave2(M) \ + sqlite3_mutex_leave( M ) + +#define s3jni_mutex_enter(M, L, Metric) \ + assert( (void*)env != (void*)L && "Invalid use of " #L); \ + s3jni_mutex_enter2( M, Metric ); \ + L = env +#define s3jni_mutex_leave(M, L) \ + assert( (void*)env == (void*)L && "Invalid use of " #L); \ + L = 0; \ + s3jni_mutex_leave2( M ) + #define S3JniEnv_mutex_assertLocked \ assert( 0 != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) #define S3JniEnv_mutex_assertLocker \ @@ -724,69 +746,58 @@ static void s3jni_incr( volatile unsigned int * const p ){ #define S3JniEnv_mutex_assertNotLocker \ assert( (env) != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) -#define S3JniEnv_mutex_enter \ - S3JniEnv_mutex_assertNotLocker; \ - sqlite3_mutex_enter( SJG.envCache.mutex ); \ - s3jni_incr(&SJG.metrics.nMutexEnv); \ - SJG.envCache.locker = env -#define S3JniEnv_mutex_leave \ - S3JniEnv_mutex_assertLocker; \ - SJG.envCache.locker = 0; \ - sqlite3_mutex_leave( SJG.envCache.mutex ) +#define S3JniEnv_mutex_enter \ + s3jni_mutex_enter( SJG.envCache.mutex, SJG.envCache.locker, nMutexEnv ) +#define S3JniEnv_mutex_leave \ + s3jni_mutex_leave( SJG.envCache.mutex, SJG.envCache.locker ) -#define S3JniAutoExt_mutex_enter \ - sqlite3_mutex_enter( SJG.autoExt.mutex ); \ - SJG.autoExt.locker = env; \ - s3jni_incr( &SJG.metrics.nMutexAutoExt ) -#define S3JniAutoExt_mutex_leave \ - assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" ); \ - sqlite3_mutex_leave( SJG.autoExt.mutex ) +#define S3JniAutoExt_mutex_enter \ + s3jni_mutex_enter( SJG.autoExt.mutex, SJG.autoExt.locker, nMutexAutoExt ) +#define S3JniAutoExt_mutex_leave \ + s3jni_mutex_leave( SJG.autoExt.mutex, SJG.autoExt.locker ) #define S3JniAutoExt_mutex_assertLocker \ assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" ) -#define S3JniGlobal_mutex_enter \ - sqlite3_mutex_enter( SJG.mutex ); \ - s3jni_incr(&SJG.metrics.nMutexGlobal); -#define S3JniGlobal_mutex_leave sqlite3_mutex_leave( SJG.mutex ) +#define S3JniGlobal_mutex_enter \ + s3jni_mutex_enter2( SJG.mutex, nMutexGlobal ) +#define S3JniGlobal_mutex_leave \ + s3jni_mutex_leave2( SJG.mutex ) -#define S3JniNph_mutex_enter \ - sqlite3_mutex_enter( SJG.nph.mutex ); \ - assert( !SJG.nph.locker && "Misuse of S3JniGlobal.nph.mutex" ); \ - s3jni_incr( &SJG.metrics.nMutexNph ); \ - SJG.nph.locker = env -#define S3JniNph_mutex_leave \ - assert( (env) == SJG.nph.locker && "Misuse of S3JniGlobal.nph.mutex" ); \ - SJG.nph.locker = 0; \ - sqlite3_mutex_leave( SJG.nph.mutex ) +#define S3JniHook_mutex_enter \ + s3jni_mutex_enter( SJG.hook.mutex, SJG.hook.locker, nMutexHook ) +#define S3JniHook_mutex_leave \ + s3jni_mutex_leave( SJG.hook.mutex, SJG.hook.locker ) + +#define S3JniNph_mutex_enter \ + s3jni_mutex_enter( SJG.nph.mutex, SJG.nph.locker, nMutexNph ) +#define S3JniNph_mutex_leave \ + s3jni_mutex_leave( SJG.nph.mutex, SJG.nph.locker ) #define S3JniDb_mutex_assertLocker \ assert( (env) == SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ) -#define S3JniDb_mutex_enter \ - sqlite3_mutex_enter( SJG.perDb.mutex ); \ - assert( 0==SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ); \ - s3jni_incr( &SJG.metrics.nMutexPerDb ); \ - SJG.perDb.locker = env; -#define S3JniDb_mutex_leave \ - assert( env == SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ); \ - SJG.perDb.locker = 0; \ - sqlite3_mutex_leave( SJG.perDb.mutex ) +#define S3JniDb_mutex_enter \ + s3jni_mutex_enter( SJG.perDb.mutex, SJG.perDb.locker, nMutexPerDb ) +#define S3JniDb_mutex_leave \ + s3jni_mutex_leave( SJG.perDb.mutex, SJG.perDb.locker ) #else /* SQLITE_THREADSAFE==0 */ +#define S3JniAutoExt_mutex_assertLocker +#define S3JniAutoExt_mutex_enter +#define S3JniAutoExt_mutex_leave +#define S3JniDb_mutex_assertLocker +#define S3JniDb_mutex_enter +#define S3JniDb_mutex_leave #define S3JniEnv_mutex_assertLocked #define S3JniEnv_mutex_assertLocker #define S3JniEnv_mutex_assertNotLocker #define S3JniEnv_mutex_enter #define S3JniEnv_mutex_leave -#define S3JniAutoExt_mutex_assertLocker -#define S3JniAutoExt_mutex_enter -#define S3JniAutoExt_mutex_leave #define S3JniGlobal_mutex_enter #define S3JniGlobal_mutex_leave +#define S3JniHook_mutex_enter +#define S3JniHook_mutex_leave #define S3JniNph_mutex_enter #define S3JniNph_mutex_leave -#define S3JniDb_mutex_assertLocker -#define S3JniDb_mutex_enter -#define S3JniDb_mutex_leave #endif /* Helpers for jstring and jbyteArray. */ @@ -1123,12 +1134,12 @@ static void s3jni__call_xDestroy(JNIEnv * const env, jobject jObj){ */ static void S3JniHook__localdup( JNIEnv * const env, S3JniHook const * const src, S3JniHook * const dest ){ - S3JniGlobal_mutex_enter; + S3JniHook_mutex_enter; *dest = *src; if(src->jObj) dest->jObj = S3JniRefLocal(src->jObj); if(src->jExtra) dest->jExtra = S3JniRefLocal(src->jExtra); dest->doXDestroy = 0; - S3JniGlobal_mutex_leave; + S3JniHook_mutex_leave; } #define S3JniHook_localdup(src,dest) S3JniHook__localdup(env,src,dest) @@ -1165,14 +1176,14 @@ static void S3JniHook__unref(JNIEnv * const env, S3JniHook * const s){ */ static S3JniHook *S3JniHook__alloc(JNIEnv * const env){ S3JniHook * p = 0; - S3JniGlobal_mutex_enter; - if( SJG.hooks.aFree ){ - p = SJG.hooks.aFree; - SJG.hooks.aFree = p->pNext; + S3JniHook_mutex_enter; + if( SJG.hook.aFree ){ + p = SJG.hook.aFree; + SJG.hook.aFree = p->pNext; p->pNext = 0; s3jni_incr(&SJG.metrics.nHookRecycled); } - S3JniGlobal_mutex_leave; + S3JniHook_mutex_leave; if( 0==p ){ p = s3jni_malloc(sizeof(S3JniHook)); if( p ){ @@ -1187,17 +1198,17 @@ static S3JniHook *S3JniHook__alloc(JNIEnv * const env){ #define S3JniHook_alloc() S3JniHook__alloc(env) /* -** The rightful fate of all results from S3JniHook_alloc(). Locks the -** global mutex. +** The rightful fate of all results from S3JniHook_alloc(). Locks on +** SJG>hooks.mutex. */ static void S3JniHook__free(JNIEnv * const env, S3JniHook * const p){ if(p){ assert( !p->pNext ); S3JniHook_unref(p); - S3JniGlobal_mutex_enter; - p->pNext = SJG.hooks.aFree; - SJG.hooks.aFree = p; - S3JniGlobal_mutex_leave; + S3JniHook_mutex_enter; + p->pNext = SJG.hook.aFree; + SJG.hook.aFree = p; + S3JniHook_mutex_leave; } } #define S3JniHook_free(hook) S3JniHook__free(env, hook) @@ -1207,10 +1218,10 @@ static void S3JniHook__free(JNIEnv * const env, S3JniHook * const p){ static void S3JniHook__free_unlocked(JNIEnv * const env, S3JniHook * const p){ if(p){ assert( !p->pNext ); - assert( p->pNext != SJG.hooks.aFree ); + assert( p->pNext != SJG.hook.aFree ); S3JniHook_unref(p); - p->pNext = SJG.hooks.aFree; - SJG.hooks.aFree = p; + p->pNext = SJG.hook.aFree; + SJG.hook.aFree = p; } } #define S3JniHook_free_unlocked(hook) S3JniHook__free_unlocked(env, hook) @@ -1751,7 +1762,8 @@ static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){ S3JniUnrefLocal(klazz); if( s->jmidxFunc ) s->type = UDF_SCALAR; else if( s->jmidxStep && s->jmidxFinal ){ - s->type = s->jmidxValue ? UDF_WINDOW : UDF_AGGREGATE; + s->type = (s->jmidxValue && s->jmidxInverse) + ? UDF_WINDOW : UDF_AGGREGATE; }else{ s->type = UDF_UNKNOWN_TYPE; } @@ -2764,7 +2776,7 @@ static void s3jni_config_sqllog(void *ignored, sqlite3 *pDb, const char *z, int S3JniHook hook = S3JniHook_empty; if( ps ){ - S3JniHook_localdup(&SJG.hooks.sqllog, &hook); + S3JniHook_localdup(&SJG.hook.sqllog, &hook); } if( !hook.jObj ) return; jArg0 = S3JniRefLocal(ps->jDb); @@ -2801,7 +2813,7 @@ S3JniApi(sqlite3_config() /* for SQLLOG */, #ifndef SQLITE_ENABLE_SQLLOG return SQLITE_MISUSE; #else - S3JniHook * const pHook = &SJG.hooks.sqllog; + S3JniHook * const pHook = &SJG.hook.sqllog; int rc = 0; S3JniGlobal_mutex_enter; @@ -4047,17 +4059,19 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)( u->pNext = 0; S3JniUdf_free(env, u, 0); } + } S3JniGlobal_mutex_leave; + S3JniHook_mutex_enter; { /* Free up S3JniHook recycling bin. */ - while( S3JniGlobal.hooks.aFree ){ - S3JniHook * const u = S3JniGlobal.hooks.aFree; - S3JniGlobal.hooks.aFree = u->pNext; + while( S3JniGlobal.hook.aFree ){ + S3JniHook * const u = S3JniGlobal.hook.aFree; + S3JniGlobal.hook.aFree = u->pNext; u->pNext = 0; assert( !u->doXDestroy ); assert( !u->jObj ); assert( !u->jExtra ); sqlite3_free( u ); } - } S3JniGlobal_mutex_leave; + } S3JniHook_mutex_leave; /* Free up env cache. */ S3JniEnv_mutex_enter; { while( SJG.envCache.aHead ){ @@ -4452,14 +4466,15 @@ JniDecl(void,1jni_1internal_1details)(JniArgsEnvClass){ "\n\tglobal = %u" "\n\tenv = %u" "\n\tnph = %u for S3JniNphOp init" + "\n\thook = %u" "\n\tperDb = %u" "\n\tautoExt list = %u" "\n\tS3JniUdf = %u (free-list)" "\n\tmetrics = %u\n", SJG.metrics.nMutexGlobal, SJG.metrics.nMutexEnv, - SJG.metrics.nMutexNph, SJG.metrics.nMutexPerDb, - SJG.metrics.nMutexAutoExt, SJG.metrics.nMutexUdf, - SJG.metrics.nMetrics); + SJG.metrics.nMutexNph, SJG.metrics.nMutexHook, + SJG.metrics.nMutexPerDb, SJG.metrics.nMutexAutoExt, + SJG.metrics.nMutexUdf, SJG.metrics.nMetrics); puts("Allocs:"); printf("\tS3JniDb: %u alloced (*%u = %u bytes), %u recycled\n", SJG.metrics.nPdbAlloc, (unsigned) sizeof(S3JniDb), @@ -5363,6 +5378,8 @@ Java_org_sqlite_jni_SQLite3Jni_init(JniArgsEnvClass){ SJG.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); s3jni_oom_fatal( SJG.mutex ); + SJG.hook.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + s3jni_oom_fatal( SJG.hook.mutex ); SJG.nph.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); s3jni_oom_fatal( SJG.nph.mutex ); SJG.envCache.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); diff --git a/manifest b/manifest index 32c1abd2c7..dff6865b86 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sa\ssuperfluous\slevel\sof\sindirection\sin\sthe\sJNI\sinternals. -D 2023-09-02T10:18:10.477 +C Duplicate\scode\sconsolidation. +D 2023-09-02T11:26:36.375 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -237,7 +237,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile dc6e78f9717470d262b4b3ec17c337834295f9df81717c1539da84106324fd1e F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c 1ce08538c568ec47ccf9e88e8b6d0e5b8a874520238d809adbfc93feb9f54d27 +F ext/jni/src/c/sqlite3-jni.c 2b274355058b64edb76cbbec8f6459ea977f56bf648becd8c4dba96b9c5147ec F ext/jni/src/c/sqlite3-jni.h c22f0189254abe26fad3ba132b484785b19a1aa96d34d30d7d8c5ffe6a9b25d1 F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436 F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4 @@ -2115,8 +2115,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 30e38173c3ece0c9f8e7a9710f46cb5e8e8ef101c04531318a7adb070242f5dd -R 5b531d67a390c107642befa040c21413 +P 8dca6f7660c15eacbda20da1c66c9ef1de36864f78750658226b1a7baf22b726 +R cd45a82215972a4be2e15156d78c2ac2 U stephan -Z 11b0834dd4cedde9630a4a43d0bbc08f +Z ff41a71811c7dc2406bc2ebbdfa8abb1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 96a63aefce..b8415855cf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8dca6f7660c15eacbda20da1c66c9ef1de36864f78750658226b1a7baf22b726 \ No newline at end of file +a1872ae959cca11d5d8bc224aaeb0b53e772d999df9924b2e9ea84ceedb99148 \ No newline at end of file