From: stephan Date: Sun, 13 Aug 2023 09:53:27 +0000 (+0000) Subject: An initial attempt at protecting the JNI global state via mutexes at the C level... X-Git-Tag: version-3.44.0~305^2~36 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=71e5694cd51bbf66546e58b52553a16fb7e842ff;p=thirdparty%2Fsqlite.git An initial attempt at protecting the JNI global state via mutexes at the C level instead of relying on Java's synchronized keyword. It seems to work but increases the run time of the single-threaded batch tester by roughly 3 times. FossilOrigin-Name: c64e6a52ac79164be37fe643a4a39bd187af198a379410def8b8419f7c2224d4 --- diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 6c60aeaf3a..4522e05b45 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -498,10 +498,14 @@ static struct { struct { S3JniEnvCache * aHead /* Linked list of in-use instances */; S3JniEnvCache * aFree /* Linked list of free instances */; + sqlite3_mutex * mutex /* mutex for aHead and aFree */; + void const * locker /* env mutex is held on this object's behalf */; } envCache; struct { S3JniDb * aUsed /* Linked list of in-use instances */; S3JniDb * aFree /* Linked list of free instances */; + sqlite3_mutex * mutex /* mutex for aUsed and aFree */; + void const * locker /* perDb mutex is held on this object's behalf */; } perDb; struct { unsigned nphCacheHits; @@ -521,21 +525,50 @@ static struct { #if S3JNI_ENABLE_AUTOEXT struct { S3JniAutoExtension *pHead /* Head of the auto-extension list */; - S3JniDb * psOpening /* 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 - behave property if they call further - db APIs. */; - int isRunning /* True while auto extensions are - running. This is used to prohibit - manipulation of the auto-extension - list while extensions are - running. */; + S3JniDb * psOpening /* 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 + behave property if they call further db + APIs. */; + int isRunning /* True while auto extensions are + running. This is used to prohibit + manipulation of the auto-extension + list while extensions are + running. */; } autoExt; #endif } S3JniGlobal; +#define MUTEX_ASSERT_LOCKER_ENV \ + assert( (env) == S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) +#define MUTEX_ASSERT_LOCKER_PDB \ + assert( 0 != S3JniGlobal.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ) +#define MUTEX_ASSERT_NOTLOCKER_ENV \ + assert( (env) != S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) +#define MUTEX_ASSERT_NOTLOCKER_PDB \ + assert( 0 == S3JniGlobal.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ) +#define MUTEX_ENTER_ENV \ + /*MARKER(("Entering ENV mutex@%p %s.\n", env, __func__));*/ \ + MUTEX_ASSERT_NOTLOCKER_ENV; \ + sqlite3_mutex_enter( S3JniGlobal.envCache.mutex ); \ + S3JniGlobal.envCache.locker = env +#define MUTEX_LEAVE_ENV \ + /*MARKER(("Leaving ENV mutex @%p %s.\n", env, __func__));*/ \ + MUTEX_ASSERT_LOCKER_ENV; \ + S3JniGlobal.envCache.locker = 0; \ + sqlite3_mutex_leave( S3JniGlobal.envCache.mutex ) +#define MUTEX_ENTER_PDB \ + /*MARKER(("Entering PerDb mutex@%p %s.\n", env, __func__));*/ \ + MUTEX_ASSERT_NOTLOCKER_PDB; \ + sqlite3_mutex_enter( S3JniGlobal.perDb.mutex ); \ + S3JniGlobal.perDb.locker = env; +#define MUTEX_LEAVE_PDB \ + /*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \ + MUTEX_ASSERT_LOCKER_PDB; \ + S3JniGlobal.perDb.locker = 0; \ + sqlite3_mutex_leave( S3JniGlobal.perDb.mutex ) + #define OOM_CHECK(VAR) if(!(VAR)) s3jni_oom(env) static void s3jni_oom(JNIEnv * const env){ (*env)->FatalError(env, "Out of memory.") /* does not return */; @@ -559,12 +592,14 @@ static void * s3jni_malloc(JNIEnv * const env, size_t n){ insofar as possible. Calls (*env)->FatalError() if allocation of an entry fails. That's hypothetically possible but "shouldn't happen." */ -FIXME_THREADING(S3JniEnvCache) static S3JniEnvCache * S3JniGlobal_env_cache(JNIEnv * const env){ - struct S3JniEnvCache * row = S3JniGlobal.envCache.aHead; + struct S3JniEnvCache * row; + MUTEX_ENTER_ENV; + row = S3JniGlobal.envCache.aHead; for( ; row; row = row->pNext ){ if( row->env == env ){ ++S3JniGlobal.metrics.envCacheHits; + MUTEX_LEAVE_ENV; return row; } } @@ -576,11 +611,7 @@ static S3JniEnvCache * S3JniGlobal_env_cache(JNIEnv * const env){ if( row->pNext ) row->pNext->pPrev = 0; }else{ row = sqlite3_malloc(sizeof(S3JniEnvCache)); - if( !row ){ - (*env)->FatalError(env, "Maintenance required: S3JniEnvCache is full.") - /* Does not return, but cc doesn't know that */; - return NULL; - } + OOM_CHECK(row); } memset(row, 0, sizeof(*row)); row->pNext = S3JniGlobal.envCache.aHead; @@ -616,11 +647,12 @@ static S3JniEnvCache * S3JniGlobal_env_cache(JNIEnv * const env){ EXCEPTION_IS_FATAL("Error getting reference to StndardCharsets class."); fUtf8 = (*env)->GetStaticFieldID(env, klazzSC, "UTF_8", "Ljava/nio/charset/Charset;"); - EXCEPTION_IS_FATAL("Error getting StndardCharsets.UTF_8 field."); + EXCEPTION_IS_FATAL("Error getting StandardCharsets.UTF_8 field."); row->g.oCharsetUtf8 = REF_G((*env)->GetStaticObjectField(env, klazzSC, fUtf8)); EXCEPTION_IS_FATAL("Error getting reference to StandardCharsets.UTF_8."); } + MUTEX_LEAVE_ENV; return row; } @@ -765,7 +797,6 @@ static jstring s3jni_text16_to_jstring(JNIEnv * const env, const void * const p, System.out.println(e.getMessage()); // Hi } */ -FIXME_THREADING(S3JniEnvCache) static char * s3jni_exception_error_msg(JNIEnv * const env, jthrowable jx ){ S3JniEnvCache * const jc = S3JniGlobal_env_cache(env); jmethodID mid; @@ -865,10 +896,10 @@ static void S3JniHook_unref(JNIEnv * const env, S3JniHook * const s, int doXDest /** Clears s's state and moves it to the free-list. */ -FIXME_THREADING(perDb) static void S3JniDb_set_aside(S3JniDb * const s){ if(s){ JNIEnv * const env = s->env; + MUTEX_ASSERT_LOCKER_PDB; assert(s->pDb && "Else this object is already in the free-list."); //MARKER(("state@%p for db@%p setting aside\n", s, s->pDb)); assert(s->pPrev != s); @@ -904,39 +935,16 @@ static void S3JniDb_set_aside(S3JniDb * const s){ //if(s->pNext) MARKER(("next: %p->pPrev@%p\n", s->pNext, s->pNext->pPrev)); } } - -/** - Requires that p has been snipped from any linked list it is - in. Clears all Java refs p holds and zeroes out p. -*/ -static void S3JniEnvCache_clear(S3JniEnvCache * const p){ - JNIEnv * const env = p->env; - if(env){ - int i; - UNREF_G(p->g.cObj); - UNREF_G(p->g.cLong); - UNREF_G(p->g.cString); - UNREF_G(p->g.oCharsetUtf8); -#ifdef SQLITE_ENABLE_FTS5 - UNREF_G(p->jFtsExt); - UNREF_G(p->jPhraseIter.klazz); -#endif - for( i = 0; i < NphCache_SIZE; ++i ){ - S3JniNphCache_clear(env, &p->nph[i]); - } - memset(p, 0, sizeof(S3JniEnvCache)); - } -} - /** Cleans up all state in S3JniGlobal.perDb for th given JNIEnv. Results are undefined if a Java-side db uses the API from the given JNIEnv after this call. */ -FIXME_THREADING(perDb) static void S3JniDb_free_for_env(JNIEnv *env){ - S3JniDb * ps = S3JniGlobal.perDb.aUsed; + S3JniDb * ps; S3JniDb * pNext = 0; + MUTEX_ENTER_PDB; + ps = S3JniGlobal.perDb.aUsed; for( ; ps; ps = pNext ){ pNext = ps->pNext; if(ps->env == env){ @@ -946,6 +954,7 @@ static void S3JniDb_free_for_env(JNIEnv *env){ pNext = pPrev; } } + MUTEX_LEAVE_PDB; } /** @@ -957,35 +966,43 @@ static void S3JniDb_free_for_env(JNIEnv *env){ what would otherwise be stale references. */ static int S3JniGlobal_env_uncache(JNIEnv * const env){ - struct S3JniEnvCache * row = S3JniGlobal.envCache.aHead; + struct S3JniEnvCache * row; + int i; + assert( 0!=S3JniGlobal.envCache.mutex && "Env mutex misuse."); + row = S3JniGlobal.envCache.aHead; for( ; row; row = row->pNext ){ if( row->env == env ){ break; } } - if( !row ) return 0; + if( !row ){ + return 0; + } if( row->pNext ) row->pNext->pPrev = row->pPrev; if( row->pPrev ) row->pPrev->pNext = row->pNext; if( S3JniGlobal.envCache.aHead == row ){ assert( !row->pPrev ); S3JniGlobal.envCache.aHead = row->pNext; } - S3JniEnvCache_clear(row); - assert( !row->pNext ); - assert( !row->pPrev ); + S3JniDb_free_for_env(env); + UNREF_G(row->g.cObj); + UNREF_G(row->g.cLong); + UNREF_G(row->g.cString); + UNREF_G(row->g.oCharsetUtf8); +#ifdef SQLITE_ENABLE_FTS5 + UNREF_G(row->jFtsExt); + UNREF_G(row->jPhraseIter.klazz); +#endif + for( i = 0; i < NphCache_SIZE; ++i ){ + S3JniNphCache_clear(env, &row->nph[i]); + } + memset(row, 0, sizeof(S3JniEnvCache)); row->pNext = S3JniGlobal.envCache.aFree; if( row->pNext ) row->pNext->pPrev = row; S3JniGlobal.envCache.aFree = row; - S3JniDb_free_for_env(env); return 1; } -static void S3JniGlobal_S3JniEnvCache_clear(void){ - while( S3JniGlobal.envCache.aHead ){ - S3JniGlobal_env_uncache( S3JniGlobal.envCache.aHead->env ); - } -} - /** Searches the NativePointerHolder cache for the given combination. If it finds one, it returns it as-is. If it doesn't AND the cache @@ -1128,14 +1145,15 @@ static void * NativePointerHolder_get(JNIEnv * env, jobject pObj, const char *zC } /** - Extracts the new S3JniDb instance from the free-list, or - allocates one if needed, associats it with pDb, and returns. - Returns NULL on OOM. pDb MUST be associated with jDb via - NativePointerHolder_set(). + Extracts the new S3JniDb instance from the free-list, or allocates + one if needed, associats it with pDb, and returns. Returns NULL on + OOM. pDb MUST, on success of the calling operation, subsequently be + associated with jDb via NativePointerHolder_set(). */ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb, jobject jDb){ S3JniDb * rv; + MUTEX_ASSERT_LOCKER_PDB; if(S3JniGlobal.perDb.aFree){ rv = S3JniGlobal.perDb.aFree; //MARKER(("state@%p for db allocating for db@%p from free-list\n", rv, pDb)); @@ -1185,62 +1203,37 @@ static void S3JniDb_dump(S3JniDb *s){ #endif /** - Returns the S3JniDb object for the given db. If allocIfNeeded is - true then a new instance will be allocated if no mapping currently - exists, else NULL is returned if no mapping is found. - - The 3rd and 4th args should normally only be non-0 for - sqlite3_open(_v2)(). For most other cases, they must be 0, in which - case the db handle will be fished out of the jDb object and NULL is - returned if jDb does not have any associated S3JniDb. - - If called with a NULL jDb and non-NULL pDb then allocIfNeeded MUST - be false and it will look for a matching db object. That usage is - required for functions, like sqlite3_context_db_handle(), which - return a (sqlite3*) but do not take one as an argument. + Returns the S3JniDb object for the given db. + + The 3rd argument should normally only be non-0 for routines which + are called from the C library and pass a native db handle instead of + a Java handle. In normal usage, the 2nd argument is a Java-side sqlite3 + object, from which the db is fished out. + + 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, int allocIfNeeded){ - S3JniDb * s = S3JniGlobal.perDb.aUsed; - if(!jDb){ - if(pDb){ - assert(!allocIfNeeded); - }else{ - return 0; +static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){ + S3JniDb * s = 0; + if(jDb || pDb){ + MUTEX_ENTER_PDB; + s = S3JniGlobal.perDb.aUsed; + if(!pDb){ + assert( jDb ); + pDb = PtrGet_sqlite3(jDb); } - } - assert(allocIfNeeded ? !!pDb : 1); - if(!allocIfNeeded && !pDb){ - pDb = PtrGet_sqlite3(jDb); - } - for( ; pDb && s; s = s->pNext){ - if(s->pDb == pDb) return s; - } - if(allocIfNeeded){ - s = S3JniDb_alloc(env, pDb, jDb); + for( ; pDb && s; s = s->pNext){ + if(s->pDb == pDb){ + break; + } + } + MUTEX_LEAVE_PDB; } return s; } -#if 0 -/** - An alternative form which searches for the S3JniDb instance for - pDb with no JNIEnv-specific info. This can be (but _should_ it be?) - called from the context of a separate JNIEnv than the one mapped - to in the returned object. Returns 0 if no match is found. -*/ -FIXME_THREADING(perDb) -static S3JniDb * S3JniDb_for_db2(sqlite3 *pDb){ - S3JniDb * s = S3JniGlobal.perDb.aUsed; - for( ; pDb && s; s = s->pNext){ - if(s->pDb == pDb) return s; - } - return 0; -} -#endif - #if S3JNI_ENABLE_AUTOEXT /** Unlink ax from S3JniGlobal.autoExt and free it. @@ -2048,7 +2041,7 @@ static int s3jni_busy_handler(void* pState, int n){ FIXME_THREADING(S3JniEnvCache) JDECL(jint,1busy_1handler)(JENV_CSELF, jobject jDb, jobject jBusy){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); int rc = 0; if(!ps) return (jint)SQLITE_NOMEM; if(jBusy){ @@ -2079,7 +2072,7 @@ JDECL(jint,1busy_1handler)(JENV_CSELF, jobject jDb, jobject jBusy){ FIXME_THREADING(S3JniEnvCache) FIXME_THREADING(perDb) JDECL(jint,1busy_1timeout)(JENV_CSELF, jobject jDb, jint ms){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); if( ps ){ S3JniHook_unref(env, &ps->busyHandler, 1); return sqlite3_busy_timeout(ps->pDb, (int)ms); @@ -2110,12 +2103,13 @@ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){ int rc = 0; S3JniDb * ps = 0; assert(version == 1 || version == 2); - ps = S3JniDb_for_db(env, jDb, 0, 0); + ps = S3JniDb_for_db(env, jDb, 0); if(ps){ - //MARKER(("close()ing db@%p\n", ps->pDb)); rc = 1==version ? (jint)sqlite3_close(ps->pDb) : (jint)sqlite3_close_v2(ps->pDb); + MUTEX_ENTER_PDB; S3JniDb_set_aside(ps) /* MUST come after close() because of ps->trace. */; + MUTEX_LEAVE_PDB; NativePointerHolder_set(env, jDb, 0, S3JniClassNames.sqlite3); } return (jint)rc; @@ -2170,7 +2164,7 @@ static void s3jni_collation_needed_impl16(void *pState, sqlite3 *pDb, FIXME_THREADING(S3JniEnvCache) FIXME_THREADING(perDb) JDECL(jint,1collation_1needed)(JENV_CSELF, jobject jDb, jobject jHook){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); jclass klazz; jobject pOld = 0; jmethodID xCallback; @@ -2288,7 +2282,7 @@ static void s3jni_rollback_hook_impl(void *pP){ FIXME_THREADING(perDb) static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,jobject jDb, jobject jHook){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); jclass klazz; jobject pOld = 0; jmethodID xCallback; @@ -2357,14 +2351,14 @@ JDECL(jboolean,1compileoption_1used)(JENV_CSELF, jstring name){ FIXME_THREADING(perDb) JDECL(jobject,1context_1db_1handle)(JENV_CSELF, jobject jpCx){ sqlite3 * const pDb = sqlite3_context_db_handle(PtrGet_sqlite3_context(jpCx)); - S3JniDb * const ps = pDb ? S3JniDb_for_db(env, 0, pDb, 0) : 0; + S3JniDb * const ps = pDb ? S3JniDb_for_db(env, 0, pDb) : 0; return ps ? ps->jDb : 0; } JDECL(jint,1create_1collation)(JENV_CSELF, jobject jDb, jstring name, jint eTextRep, jobject oCollation){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); jclass klazz; int rc; const char *zName; @@ -2457,7 +2451,7 @@ JDECL(jint,1create_1function)(JENV_CSELF, jobject jDb, jstring jFuncName, JDECL(int,1db_1config__Lorg_sqlite_jni_sqlite3_2ILjava_lang_String_2)( JENV_CSELF, jobject jDb, jint op, jstring jStr ){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); int rc; char *zStr; @@ -2489,7 +2483,7 @@ FIXME_THREADING(perDb) JDECL(jint,1db_1config__Lorg_sqlite_jni_sqlite3_2IILorg_sqlite_jni_OutputPointer_Int32_2)( JENV_CSELF, jobject jDb, jint op, jint onOff, jobject jOut ){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); int rc; switch( ps ? op : 0 ){ case SQLITE_DBCONFIG_ENABLE_FKEY: @@ -2538,7 +2532,7 @@ JDECL(jint,1db_1config__Lorg_sqlite_jni_sqlite3_2IILorg_sqlite_jni_OutputPointer } JDECL(jstring,1db_1filename)(JENV_CSELF, jobject jDb, jstring jDbName){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); S3JniEnvCache * const jc = S3JniGlobal_env_cache(env); char *zDbName; jstring jRv = 0; @@ -2657,7 +2651,9 @@ static int s3jni_open_pre(JNIEnv * const env, S3JniEnvCache **jc, *zDbName = 0; return SQLITE_NOMEM; } + MUTEX_ENTER_PDB; *ps = S3JniDb_alloc(env, 0, *jDb); + MUTEX_LEAVE_PDB; #if S3JNI_ENABLE_AUTOEXT if(*ps){ assert(!S3JniGlobal.autoExt.psOpening); @@ -2688,15 +2684,12 @@ static int s3jni_open_post(JNIEnv * const env, S3JniDb * ps, #endif if(*ppDb){ assert(ps->jDb); -#if S3JNI_ENABLE_AUTOEXT - //MARKER(("*autoExt.pHead=%p, ppDb=%p, ps->pDb=%p\n", S3JniGlobal.autoExt.pHead, *ppDb, ps->pDb)); - // invalid when an autoext triggers another open(): - // assert( S3JniGlobal.autoExt.pHead ? *ppDb==ps->pDb : 0==ps->pDb ); -#endif ps->pDb = *ppDb; NativePointerHolder_set(env, ps->jDb, *ppDb, S3JniClassNames.sqlite3); }else{ + MUTEX_ENTER_PDB; S3JniDb_set_aside(ps); + MUTEX_LEAVE_PDB; ps = 0; } OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0); @@ -2845,7 +2838,7 @@ static int s3jni_progress_handler_impl(void *pP){ } JDECL(void,1progress_1handler)(JENV_CSELF,jobject jDb, jint n, jobject jProgress){ - S3JniDb * ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * ps = S3JniDb_for_db(env, jDb, 0); jclass klazz; jmethodID xCallback; if( n<1 || !jProgress ){ @@ -3101,7 +3094,7 @@ static int s3jni_xAuth(void* pState, int op,const char*z0, const char*z1, } JDECL(jint,1set_1authorizer)(JENV_CSELF,jobject jDb, jobject jHook){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); S3JniHook * const pHook = ps ? &ps->authHook : 0; if( !ps ) return SQLITE_MISUSE; @@ -3195,7 +3188,11 @@ JDECL(jint,1strlike)(JENV_CSELF, jbyteArray baG, jbyteArray baT, jint escChar){ } JDECL(jint,1shutdown)(JENV_CSELF){ - S3JniGlobal_S3JniEnvCache_clear(); + MUTEX_ENTER_ENV; + while( S3JniGlobal.envCache.aHead ){ + S3JniGlobal_env_uncache( S3JniGlobal.envCache.aHead->env ); + } + MUTEX_LEAVE_ENV; /* Do not clear S3JniGlobal.jvm: it's legal to call sqlite3_initialize() again to restart the lib. */ return sqlite3_shutdown(); @@ -3279,7 +3276,7 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){ } JDECL(jint,1trace_1v2)(JENV_CSELF,jobject jDb, jint traceMask, jobject jTracer){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); jclass klazz; if( !traceMask || !jTracer ){ if(ps){ @@ -3330,7 +3327,7 @@ static void s3jni_update_hook_impl(void * pState, int opId, const char *zDb, JDECL(jobject,1update_1hook)(JENV_CSELF, jobject jDb, jobject jHook){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); jclass klazz; jobject pOld = 0; jmethodID xCallback; @@ -3635,7 +3632,7 @@ static fts5_api *s3jni_fts5_api_from_db(sqlite3 *db){ } JDECLFtsApi(jobject,getInstanceForDb)(JENV_CSELF,jobject jDb){ - S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0); + S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0); jobject rv = 0; if(!ps) return 0; else if(ps->jFtsApi){ @@ -4338,7 +4335,11 @@ Java_org_sqlite_jni_tester_SQLTester_installCustomExtensions(JENV_CSELF){ */ JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv(JENV_CSELF){ - return S3JniGlobal_env_uncache(env) ? JNI_TRUE : JNI_FALSE; + int rc; + MUTEX_ENTER_ENV; + rc = S3JniGlobal_env_uncache(env); + MUTEX_LEAVE_ENV; + return rc ? JNI_TRUE : JNI_FALSE; } /** @@ -4402,6 +4403,10 @@ Java_org_sqlite_jni_SQLite3Jni_init(JENV_CSELF){ (*env)->FatalError(env, "GetJavaVM() failure shouldn't be possible."); return; } + S3JniGlobal.envCache.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + OOM_CHECK( S3JniGlobal.envCache.mutex ); + S3JniGlobal.perDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + OOM_CHECK( S3JniGlobal.perDb.mutex ); #if 0 /* Just for sanity checking... */ (void)S3JniGlobal_env_cache(env); diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index 6722085fdd..5d741859f1 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -1443,6 +1443,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text64 (JNIEnv *, jclass, jobject, jbyteArray, jlong, jint); +/* + * Class: org_sqlite_jni_SQLite3Jni + * Method: sqlite3_shutdown + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1shutdown + (JNIEnv *, jclass); + /* * Class: org_sqlite_jni_SQLite3Jni * Method: sqlite3_status @@ -1731,14 +1739,6 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1frombind JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1value_1subtype (JNIEnv *, jclass, jobject); -/* - * Class: org_sqlite_jni_SQLite3Jni - * Method: sqlite3_shutdown - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1shutdown - (JNIEnv *, jclass); - /* * Class: org_sqlite_jni_SQLite3Jni * Method: sqlite3_do_something_for_developer diff --git a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java index adad718145..e7aa10ebae 100644 --- a/ext/jni/src/org/sqlite/jni/SQLite3Jni.java +++ b/ext/jni/src/org/sqlite/jni/SQLite3Jni.java @@ -195,7 +195,7 @@ public final class SQLite3Jni { Achtung: it is as yet unknown whether auto extensions registered from one JNIEnv (thread) can be safely called from another. */ - public static synchronized native int sqlite3_auto_extension(@NotNull AutoExtension callback); + public static native int sqlite3_auto_extension(@NotNull AutoExtension callback); public static int sqlite3_bind_blob( @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data @@ -205,27 +205,27 @@ public final class SQLite3Jni { : sqlite3_bind_blob(stmt, ndx, data, data.length); } - private static synchronized native int sqlite3_bind_blob( + private static native int sqlite3_bind_blob( @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int n ); - public static synchronized native int sqlite3_bind_double( + public static native int sqlite3_bind_double( @NotNull sqlite3_stmt stmt, int ndx, double v ); - public static synchronized native int sqlite3_bind_int( + public static native int sqlite3_bind_int( @NotNull sqlite3_stmt stmt, int ndx, int v ); - public static synchronized native int sqlite3_bind_int64( + public static native int sqlite3_bind_int64( @NotNull sqlite3_stmt stmt, int ndx, long v ); - public static synchronized native int sqlite3_bind_null( + public static native int sqlite3_bind_null( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native int sqlite3_bind_parameter_count( + public static native int sqlite3_bind_parameter_count( @NotNull sqlite3_stmt stmt ); @@ -233,7 +233,7 @@ public final class SQLite3Jni { /** A level of indirection required to ensure that the input to the C-level function of the same name is a NUL-terminated UTF-8 string. */ - private static synchronized native int sqlite3_bind_parameter_index( + private static native int sqlite3_bind_parameter_index( @NotNull sqlite3_stmt stmt, byte[] paramName ); @@ -265,15 +265,15 @@ public final class SQLite3Jni { SQLITE_TRANSIENT for the final parameter and (B) behaves like sqlite3_bind_null() if the data argument is null. */ - private static synchronized native int sqlite3_bind_text( + private static native int sqlite3_bind_text( @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int maxBytes ); - public static synchronized native int sqlite3_bind_zeroblob( + public static native int sqlite3_bind_zeroblob( @NotNull sqlite3_stmt stmt, int ndx, int n ); - public static synchronized native int sqlite3_bind_zeroblob64( + public static native int sqlite3_bind_zeroblob64( @NotNull sqlite3_stmt stmt, int ndx, long n ); @@ -283,11 +283,11 @@ public final class SQLite3Jni { to clear the busy handler. Calling this multiple times with the same object is a no-op on the second and subsequent calls. */ - public static synchronized native int sqlite3_busy_handler( + public static native int sqlite3_busy_handler( @NotNull sqlite3 db, @Nullable BusyHandler handler ); - public static synchronized native int sqlite3_busy_timeout( + public static native int sqlite3_busy_timeout( @NotNull sqlite3 db, int ms ); @@ -296,63 +296,63 @@ 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 synchronized native boolean sqlite3_cancel_auto_extension( + public static native boolean sqlite3_cancel_auto_extension( @NotNull AutoExtension ax ); - public static synchronized native int sqlite3_changes( + public static native int sqlite3_changes( @NotNull sqlite3 db ); - public static synchronized native long sqlite3_changes64( + public static native long sqlite3_changes64( @NotNull sqlite3 db ); - public static synchronized native int sqlite3_clear_bindings( + public static native int sqlite3_clear_bindings( @NotNull sqlite3_stmt stmt ); - public static synchronized native int sqlite3_close( + public static native int sqlite3_close( @NotNull sqlite3 db ); - public static synchronized native int sqlite3_close_v2( + public static native int sqlite3_close_v2( @NotNull sqlite3 db ); - public static synchronized native byte[] sqlite3_column_blob( + public static native byte[] sqlite3_column_blob( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native int sqlite3_column_bytes( + public static native int sqlite3_column_bytes( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native int sqlite3_column_bytes16( + public static native int sqlite3_column_bytes16( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native int sqlite3_column_count( + public static native int sqlite3_column_count( @NotNull sqlite3_stmt stmt ); - public static synchronized native double sqlite3_column_double( + public static native double sqlite3_column_double( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native int sqlite3_column_int( + public static native int sqlite3_column_int( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native long sqlite3_column_int64( + public static native long sqlite3_column_int64( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native String sqlite3_column_name( + public static native String sqlite3_column_name( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native String sqlite3_column_database_name( + public static native String sqlite3_column_database_name( @NotNull sqlite3_stmt stmt, int ndx ); @@ -385,11 +385,11 @@ public final class SQLite3Jni { return type.isInstance(o) ? (T)o : null; } - public static synchronized native String sqlite3_column_origin_name( + public static native String sqlite3_column_origin_name( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native String sqlite3_column_table_name( + public static native String sqlite3_column_table_name( @NotNull sqlite3_stmt stmt, int ndx ); @@ -398,7 +398,7 @@ public final class SQLite3Jni { This API includes no functions for working with Java's Modified UTF-8. */ - public static synchronized native String sqlite3_column_text16( + public static native String sqlite3_column_text16( @NotNull sqlite3_stmt stmt, int ndx ); @@ -406,7 +406,7 @@ public final class SQLite3Jni { Returns the given column's contents as UTF-8-encoded (not MUTF-8) text. Use sqlite3_column_text16() to fetch the text */ - public static synchronized native byte[] sqlite3_column_text( + public static native byte[] sqlite3_column_text( @NotNull sqlite3_stmt stmt, int ndx ); @@ -447,11 +447,11 @@ public final class SQLite3Jni { // return rv; // } - public static synchronized native int sqlite3_column_type( + public static native int sqlite3_column_type( @NotNull sqlite3_stmt stmt, int ndx ); - public static synchronized native sqlite3_value sqlite3_column_value( + public static native sqlite3_value sqlite3_column_value( @NotNull sqlite3_stmt stmt, int ndx ); @@ -459,7 +459,7 @@ public final class SQLite3Jni { This functions like C's sqlite3_collation_needed16() because Java's string type is compatible with that interface. */ - public static synchronized native int sqlite3_collation_needed( + public static native int sqlite3_collation_needed( @NotNull sqlite3 db, @Nullable CollationNeeded callback ); @@ -467,11 +467,11 @@ public final class SQLite3Jni { Returns the db handle passed to sqlite3_open() or sqlite3_open_v2(), as opposed to a new wrapper object. */ - public static synchronized native sqlite3 sqlite3_context_db_handle( + public static native sqlite3 sqlite3_context_db_handle( @NotNull sqlite3_context cx ); - public static synchronized native CommitHook sqlite3_commit_hook( + public static native CommitHook sqlite3_commit_hook( @NotNull sqlite3 db, @Nullable CommitHook hook ); @@ -483,7 +483,7 @@ public final class SQLite3Jni { @NotNull String optName ); - public static synchronized native int sqlite3_create_collation( + public static native int sqlite3_create_collation( @NotNull sqlite3 db, @NotNull String name, int eTextRep, @NotNull Collation col ); @@ -496,16 +496,16 @@ public final class SQLite3Jni { SQLFunction's inner classes (Scalar, Aggregate, and Window) for details. */ - public static synchronized native int sqlite3_create_function( + public static native int sqlite3_create_function( @NotNull sqlite3 db, @NotNull String functionName, int nArg, int eTextRep, @NotNull SQLFunction func ); - public static synchronized native int sqlite3_data_count( + public static native int sqlite3_data_count( @NotNull sqlite3_stmt stmt ); - public static synchronized native String sqlite3_db_filename( + public static native String sqlite3_db_filename( @NotNull sqlite3 db, @NotNull String dbName ); @@ -514,7 +514,7 @@ public final class SQLite3Jni { variadic arguments. Returns SQLITE_MISUSE if op is not one of the SQLITE_DBCONFIG_... options which uses this call form. */ - public static synchronized native int sqlite3_db_config( + public static native int sqlite3_db_config( @NotNull sqlite3 db, int op, int onOff, @Nullable OutputPointer.Int32 out ); @@ -525,37 +525,37 @@ public final class SQLite3Jni { SQLITE_DBCONFIG_MAINDBNAME, but that set of options may be extended in future versions. */ - public static synchronized native int sqlite3_db_config( + public static native int sqlite3_db_config( @NotNull sqlite3 db, int op, @NotNull String val ); - public static synchronized native int sqlite3_db_status( + public static native int sqlite3_db_status( @NotNull sqlite3 db, int op, @NotNull OutputPointer.Int32 pCurrent, @NotNull OutputPointer.Int32 pHighwater, boolean reset ); - public static synchronized native int sqlite3_errcode(@NotNull sqlite3 db); + public static native int sqlite3_errcode(@NotNull sqlite3 db); - public static synchronized native String sqlite3_expanded_sql(@NotNull sqlite3_stmt stmt); + public static native String sqlite3_expanded_sql(@NotNull sqlite3_stmt stmt); - public static synchronized native int sqlite3_extended_errcode(@NotNull sqlite3 db); + public static native int sqlite3_extended_errcode(@NotNull sqlite3 db); - public static synchronized native boolean sqlite3_extended_result_codes( + public static native boolean sqlite3_extended_result_codes( @NotNull sqlite3 db, boolean onoff ); - public static synchronized native String sqlite3_errmsg(@NotNull sqlite3 db); + public static native String sqlite3_errmsg(@NotNull sqlite3 db); - public static synchronized native String sqlite3_errstr(int resultCode); + public static native String sqlite3_errstr(int resultCode); /** Note that the offset values assume UTF-8-encoded SQL. */ - public static synchronized native int sqlite3_error_offset(@NotNull sqlite3 db); + public static native int sqlite3_error_offset(@NotNull sqlite3 db); - public static synchronized native int sqlite3_finalize(@NotNull sqlite3_stmt stmt); + public static native int sqlite3_finalize(@NotNull sqlite3_stmt stmt); - public static synchronized native int sqlite3_initialize(); + public static native int sqlite3_initialize(); /** Design note/FIXME: we have a problem vis-a-vis 'synchronized' @@ -576,11 +576,11 @@ public final class SQLite3Jni { //! See sqlite3_interrupt() for threading concerns. public static native boolean sqlite3_is_interrupted(@NotNull sqlite3 db); - public static synchronized native long sqlite3_last_insert_rowid(@NotNull sqlite3 db); + public static native long sqlite3_last_insert_rowid(@NotNull sqlite3 db); - public static synchronized native String sqlite3_libversion(); + public static native String sqlite3_libversion(); - public static synchronized native int sqlite3_libversion_number(); + public static native int sqlite3_libversion_number(); /** Works like its C counterpart and makes the native pointer of the @@ -601,11 +601,11 @@ public final class SQLite3Jni { or sqlite3_open_v2() so that they have a predictible object to pass to, e.g., the sqlite3_collation_needed() callback. */ - public static synchronized native int sqlite3_open( + public static native int sqlite3_open( @Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb ); - public static synchronized native int sqlite3_open_v2( + public static native int sqlite3_open_v2( @Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb, int flags, @Nullable String zVfs ); @@ -629,7 +629,7 @@ public final class SQLite3Jni { necessary, however, and overloads are provided which gloss over that. */ - private static synchronized native int sqlite3_prepare( + private static native int sqlite3_prepare( @NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int maxBytes, @NotNull OutputPointer.sqlite3_stmt outStmt, @Nullable OutputPointer.Int32 pTailOffset @@ -658,7 +658,7 @@ public final class SQLite3Jni { return sqlite3_prepare(db, utf8, utf8.length, outStmt, null); } - private static synchronized native int sqlite3_prepare_v2( + private static native int sqlite3_prepare_v2( @NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int maxBytes, @NotNull OutputPointer.sqlite3_stmt outStmt, @Nullable OutputPointer.Int32 pTailOffset @@ -687,7 +687,7 @@ public final class SQLite3Jni { return sqlite3_prepare_v2(db, utf8, utf8.length, outStmt, null); } - private static synchronized native int sqlite3_prepare_v3( + private static native int sqlite3_prepare_v3( @NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int maxBytes, int prepFlags, @NotNull OutputPointer.sqlite3_stmt outStmt, @Nullable OutputPointer.Int32 pTailOffset @@ -716,22 +716,22 @@ public final class SQLite3Jni { return sqlite3_prepare_v3(db, utf8, utf8.length, prepFlags, outStmt, null); } - public static synchronized native void sqlite3_progress_handler( + public static native void sqlite3_progress_handler( @NotNull sqlite3 db, int n, @Nullable ProgressHandler h ); //TODO??? void *sqlite3_preupdate_hook(...) and friends - public static synchronized native int sqlite3_reset(@NotNull sqlite3_stmt stmt); + public static native int sqlite3_reset(@NotNull sqlite3_stmt stmt); /** Works like the C API except that it has no side effects if auto extensions are currently running. (The JNI-level list of extensions cannot be manipulated while it is being traversed.) */ - public static synchronized native void sqlite3_reset_auto_extension(); + public static native void sqlite3_reset_auto_extension(); - public static synchronized native void sqlite3_result_double( + public static native void sqlite3_result_double( @NotNull sqlite3_context cx, double v ); @@ -742,7 +742,7 @@ public final class SQLite3Jni { results in the C-level sqlite3_result_error() being called with a complaint about the invalid argument. */ - private static synchronized native void sqlite3_result_error( + private static native void sqlite3_result_error( @NotNull sqlite3_context cx, @Nullable byte[] msg, int eTextRep ); @@ -785,27 +785,27 @@ public final class SQLite3Jni { sqlite3_result_error16(cx, e.getMessage()); } - public static synchronized native void sqlite3_result_error_toobig( + public static native void sqlite3_result_error_toobig( @NotNull sqlite3_context cx ); - public static synchronized native void sqlite3_result_error_nomem( + public static native void sqlite3_result_error_nomem( @NotNull sqlite3_context cx ); - public static synchronized native void sqlite3_result_error_code( + public static native void sqlite3_result_error_code( @NotNull sqlite3_context cx, int c ); - public static synchronized native void sqlite3_result_null( + public static native void sqlite3_result_null( @NotNull sqlite3_context cx ); - public static synchronized native void sqlite3_result_int( + public static native void sqlite3_result_int( @NotNull sqlite3_context cx, int v ); - public static synchronized native void sqlite3_result_int64( + public static native void sqlite3_result_int64( @NotNull sqlite3_context cx, long v ); @@ -825,7 +825,7 @@ public final class SQLite3Jni { Note that there is no sqlite3_bind_java_object() counterpart. */ - public static synchronized native void sqlite3_result_java_object( + public static native void sqlite3_result_java_object( @NotNull sqlite3_context cx, @NotNull Object o ); @@ -883,19 +883,19 @@ public final class SQLite3Jni { sqlite3_result_text(cx, v); } - public static synchronized native void sqlite3_result_value( + public static native void sqlite3_result_value( @NotNull sqlite3_context cx, @NotNull sqlite3_value v ); - public static synchronized native void sqlite3_result_zeroblob( + public static native void sqlite3_result_zeroblob( @NotNull sqlite3_context cx, int n ); - public static synchronized native int sqlite3_result_zeroblob64( + public static native int sqlite3_result_zeroblob64( @NotNull sqlite3_context cx, long n ); - private static synchronized native void sqlite3_result_blob( + private static native void sqlite3_result_blob( @NotNull sqlite3_context cx, @Nullable byte[] blob, int maxLen ); @@ -915,7 +915,7 @@ public final class SQLite3Jni { If maxLen is larger than blob.length, it is truncated to that value. If it is negative, results are undefined. */ - private static synchronized native void sqlite3_result_blob64( + private static native void sqlite3_result_blob64( @NotNull sqlite3_context cx, @Nullable byte[] blob, long maxLen ); @@ -925,7 +925,7 @@ public final class SQLite3Jni { sqlite3_result_blob64(cx, blob, (long)(null==blob ? 0 : blob.length)); } - private static synchronized native void sqlite3_result_text( + private static native void sqlite3_result_text( @NotNull sqlite3_context cx, @Nullable byte[] text, int maxLen ); @@ -959,17 +959,23 @@ public final class SQLite3Jni { text.length, it is silently truncated to text.length. If it is negative, results are undefined. */ - private static synchronized native void sqlite3_result_text64( + private static native void sqlite3_result_text64( @NotNull sqlite3_context cx, @Nullable byte[] text, long maxLength, int encoding ); - public static synchronized native int sqlite3_status( + /** + Cleans up all per-JNIEnv and per-db state managed by the library + then calls the C-native sqlite3_shutdown(). + */ + public static synchronized native int sqlite3_shutdown(); + + public static native int sqlite3_status( int op, @NotNull OutputPointer.Int32 pCurrent, @NotNull OutputPointer.Int32 pHighwater, boolean reset ); - public static synchronized native int sqlite3_status64( + public static native int sqlite3_status64( int op, @NotNull OutputPointer.Int64 pCurrent, @NotNull OutputPointer.Int64 pHighwater, boolean reset ); @@ -1025,32 +1031,32 @@ public final class SQLite3Jni { sqlite3_result_text64(cx, b, b.length, SQLITE_UTF16BE); } - public static synchronized native RollbackHook sqlite3_rollback_hook( + public static native RollbackHook sqlite3_rollback_hook( @NotNull sqlite3 db, @Nullable RollbackHook hook ); //! Sets or unsets (if auth is null) the current authorizer. - public static synchronized native int sqlite3_set_authorizer( + public static native int sqlite3_set_authorizer( @NotNull sqlite3 db, @Nullable Authorizer auth ); - public static synchronized native void sqlite3_set_last_insert_rowid( + public static native void sqlite3_set_last_insert_rowid( @NotNull sqlite3 db, long rowid ); - public static synchronized native int sqlite3_sleep(int ms); + public static native int sqlite3_sleep(int ms); - public static synchronized native String sqlite3_sourceid(); + public static native String sqlite3_sourceid(); - public static synchronized native String sqlite3_sql(@NotNull sqlite3_stmt stmt); + public static native String sqlite3_sql(@NotNull sqlite3_stmt stmt); - public static synchronized native int sqlite3_step(@NotNull sqlite3_stmt stmt); + public static native int sqlite3_step(@NotNull sqlite3_stmt stmt); /** Internal impl of the public sqlite3_strglob() method. Neither argument may be NULL and both _MUST_ be NUL-terminated. */ - private static synchronized native int sqlite3_strglob( + private static native int sqlite3_strglob( @NotNull byte[] glob, @NotNull byte[] txt ); @@ -1067,7 +1073,7 @@ public final class SQLite3Jni { Internal impl of the public sqlite3_strlike() method. Neither argument may be NULL and both _MUST_ be NUL-terminated. */ - private static synchronized native int sqlite3_strlike( + private static native int sqlite3_strlike( @NotNull byte[] glob, @NotNull byte[] txt, int escChar ); @@ -1081,11 +1087,11 @@ public final class SQLite3Jni { ); } - public static synchronized native int sqlite3_threadsafe(); + public static native int sqlite3_threadsafe(); - public static synchronized native int sqlite3_total_changes(@NotNull sqlite3 db); + public static native int sqlite3_total_changes(@NotNull sqlite3 db); - public static synchronized native long sqlite3_total_changes64(@NotNull sqlite3 db); + public static native long sqlite3_total_changes64(@NotNull sqlite3 db); /** Works like C's sqlite3_trace_v2() except that the 3rd argument to that @@ -1097,33 +1103,33 @@ public final class SQLite3Jni { mapping state fails and SQLITE_ERROR if the given callback object cannot be processed propertly (i.e. an internal error). */ - public static synchronized native int sqlite3_trace_v2( + public static native int sqlite3_trace_v2( @NotNull sqlite3 db, int traceMask, @Nullable Tracer tracer ); - public static synchronized native UpdateHook sqlite3_update_hook( + public static native UpdateHook sqlite3_update_hook( sqlite3 db, UpdateHook hook ); - public static synchronized native byte[] sqlite3_value_blob(@NotNull sqlite3_value v); + public static native byte[] sqlite3_value_blob(@NotNull sqlite3_value v); - public static synchronized native int sqlite3_value_bytes(@NotNull sqlite3_value v); + public static native int sqlite3_value_bytes(@NotNull sqlite3_value v); - public static synchronized native int sqlite3_value_bytes16(@NotNull sqlite3_value v); + public static native int sqlite3_value_bytes16(@NotNull sqlite3_value v); - public static synchronized native double sqlite3_value_double(@NotNull sqlite3_value v); + public static native double sqlite3_value_double(@NotNull sqlite3_value v); - public static synchronized native sqlite3_value sqlite3_value_dupe( + public static native sqlite3_value sqlite3_value_dupe( @NotNull sqlite3_value v ); - public static synchronized native int sqlite3_value_encoding(@NotNull sqlite3_value v); + public static native int sqlite3_value_encoding(@NotNull sqlite3_value v); - public static synchronized native void sqlite3_value_free(@Nullable sqlite3_value v); + public static native void sqlite3_value_free(@Nullable sqlite3_value v); - public static synchronized native int sqlite3_value_int(@NotNull sqlite3_value v); + public static native int sqlite3_value_int(@NotNull sqlite3_value v); - public static synchronized native long sqlite3_value_int64(@NotNull sqlite3_value v); + public static native long sqlite3_value_int64(@NotNull sqlite3_value v); /** If the given value was set using sqlite3_result_java_value() then @@ -1132,7 +1138,7 @@ public final class SQLite3Jni { It is up to the caller to inspect the object to determine its type, and cast it if necessary. */ - public static synchronized native Object sqlite3_value_java_object( + public static native Object sqlite3_value_java_object( @NotNull sqlite3_value v ); @@ -1153,41 +1159,35 @@ public final class SQLite3Jni { See sqlite3_value_text_utf8() for how to extract text in standard UTF-8. */ - public static synchronized native String sqlite3_value_text(@NotNull sqlite3_value v); + public static native String sqlite3_value_text(@NotNull sqlite3_value v); /** The sqlite3_value counterpart of sqlite3_column_text_utf8(). */ - public static synchronized native byte[] sqlite3_value_text_utf8(@NotNull sqlite3_value v); + public static native byte[] sqlite3_value_text_utf8(@NotNull sqlite3_value v); - public static synchronized native byte[] sqlite3_value_text16(@NotNull sqlite3_value v); + public static native byte[] sqlite3_value_text16(@NotNull sqlite3_value v); - public static synchronized native byte[] sqlite3_value_text16le(@NotNull sqlite3_value v); + public static native byte[] sqlite3_value_text16le(@NotNull sqlite3_value v); - public static synchronized native byte[] sqlite3_value_text16be(@NotNull sqlite3_value v); + public static native byte[] sqlite3_value_text16be(@NotNull sqlite3_value v); - public static synchronized native int sqlite3_value_type(@NotNull sqlite3_value v); + public static native int sqlite3_value_type(@NotNull sqlite3_value v); - public static synchronized native int sqlite3_value_numeric_type(@NotNull sqlite3_value v); + public static native int sqlite3_value_numeric_type(@NotNull sqlite3_value v); - public static synchronized native int sqlite3_value_nochange(@NotNull sqlite3_value v); + public static native int sqlite3_value_nochange(@NotNull sqlite3_value v); - public static synchronized native int sqlite3_value_frombind(@NotNull sqlite3_value v); + public static native int sqlite3_value_frombind(@NotNull sqlite3_value v); - public static synchronized native int sqlite3_value_subtype(@NotNull sqlite3_value v); - - /** - Cleans up all per-JNIEnv and per-db state managed by the library - then calls the C-native sqlite3_shutdown(). - */ - public static synchronized native int sqlite3_shutdown(); + public static native int sqlite3_value_subtype(@NotNull sqlite3_value v); /** This is NOT part of the public API. It exists solely as a place to hook in arbitrary C-side code during development and testing of this library. */ - public static synchronized native void sqlite3_do_something_for_developer(); + public static native void sqlite3_do_something_for_developer(); ////////////////////////////////////////////////////////////////////// // SQLITE_... constants follow... diff --git a/manifest b/manifest index 0c792ccae0..d3b949dbf9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bind\ssqlite3_interrupt()\sand\ssqlite3_is_interrupted()\sto\sJNI\sbut\swith\scaveats\sregarding\smutexing\sof\sthe\sJNIEnv\scache.\sAdd\sa\sloud\swarning\sto\sthe\sJNI\s'dist'\starget\sthat\sit\sshould\sbe\sbuilt\swith\sJDK8\s(a.k.a.\sJava\s1.8)\sfor\scompatibility\sreasons. -D 2023-08-12T23:47:58.408 +C An\sinitial\sattempt\sat\sprotecting\sthe\sJNI\sglobal\sstate\svia\smutexes\sat\sthe\sC\slevel\sinstead\sof\srelying\son\sJava's\ssynchronized\skeyword.\sIt\sseems\sto\swork\sbut\sincreases\sthe\srun\stime\sof\sthe\ssingle-threaded\sbatch\stester\sby\sroughly\s3\stimes. +D 2023-08-13T09:53:27.824 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -234,8 +234,8 @@ 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 1d3bb5113ba4dd7f8645fcc4c669155931e44e234816f528642a738914dd45a4 -F ext/jni/src/c/sqlite3-jni.h 11bf3ab9682f5c393e6ac6a3ddb0fdf7b8dd40f7c77f9ef122d3e5c011a5d329 +F ext/jni/src/c/sqlite3-jni.c 93fbeed06441352df68f6c0e4bc2cd895e81d8550dc9972cafb30621958b4784 +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 F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c @@ -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 1652af40fc0acb7a140dbe32e3146f980c37c28454b5115a4d0856cbdbc52696 +F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 7933fabc267dbfdccb784563d8c404f90275fe9418e8cd6c43c584bc9c57f70f 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 48b13edcec6935bf125b265b41a3e6f7b2407afff89d5b4daa2939e3c5679ca0 -R 122775c5939e6f1540fadefe535658be +P fbf99a2423dd20e4544bdeea85f714e9368ce3b92fefe97efb39a0fb4a557abe +R 42a3d0d4c63d13c26ffa7bd8f71380ed U stephan -Z a13d97b8681eef4145a4ab842cd3a9d2 +Z 5906c49c68c9155fc27b7d9430c5551e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 97ea0d6766..684bcd68e8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fbf99a2423dd20e4544bdeea85f714e9368ce3b92fefe97efb39a0fb4a557abe \ No newline at end of file +c64e6a52ac79164be37fe643a4a39bd187af198a379410def8b8419f7c2224d4 \ No newline at end of file